> ## Documentation Index
> Fetch the complete documentation index at: https://embed.usesticker.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Security

> Security best practices for your Sticker integration

## Overview

Security is paramount when integrating third-party services. This guide covers security best practices to protect your users and data.

## API Key Security

### Storage

<AccordionGroup>
  <Accordion title="Environment Variables" icon="shield-check">
    **DO:**

    ```bash theme={null}
    # .env file (never commit!)
    STICKER_API_KEY=sk_live_abc123...
    ```

    **DON'T:**

    ```javascript theme={null}
    // NEVER hardcode keys
    const apiKey = 'sk_live_abc123...'; // ❌
    ```
  </Accordion>

  <Accordion title="Secrets Management" icon="vault">
    Use dedicated secrets management for production:

    * AWS Secrets Manager
    * HashiCorp Vault
    * Azure Key Vault
    * Google Cloud Secret Manager

    ```javascript theme={null}
    // Example with AWS Secrets Manager
    const AWS = require('aws-sdk');
    const secretsManager = new AWS.SecretsManager();

    async function getAPIKey() {
      const secret = await secretsManager.getSecretValue({
        SecretId: 'sticker/api-key'
      }).promise();
      
      return JSON.parse(secret.SecretString).apiKey;
    }
    ```
  </Accordion>

  <Accordion title="Key Rotation" icon="rotate">
    Rotate API keys if compromised:

    1. Contact Sticker support immediately
    2. We'll issue a new key
    3. Update key in secrets manager
    4. Deploy configuration update
    5. Old key is invalidated
  </Accordion>
</AccordionGroup>

### Access Control

Limit who can access API keys:

```javascript theme={null}
// Use least privilege principle
const apiKey = process.env.STICKER_API_KEY;

// Only backend services should have access
if (typeof window !== 'undefined') {
  throw new Error('API key cannot be accessed in browser');
}
```

<Warning>
  **Never expose API keys in:**

  * Client-side JavaScript
  * Mobile app code
  * Public repositories
  * Log files
  * Error messages
  * URLs or query parameters
</Warning>

## Request Security

### HTTPS Only

Always use HTTPS for API requests:

```javascript theme={null}
// Good
const API_URL = 'https://api.usesticker.com/v1';

// Bad - never use HTTP
const API_URL = 'http://api.usesticker.com/v1'; // ❌
```

### Input Validation

Validate all inputs before sending to API:

```javascript theme={null}
function validateOrganization(org) {
  const errors = [];
  
  // Email validation
  if (!org.email || !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(org.email)) {
    errors.push('Invalid email format');
  }
  
  // Required fields
  if (!org.name || org.name.trim().length === 0) {
    errors.push('Organization name is required');
  }
  
  // State validation
  const validStates = ['AL', 'AK', 'AZ', /* ... all states */];
  org.shippingLocations?.forEach((loc, idx) => {
    if (!loc.address.province) {
      errors.push(`Address ${idx + 1} is missing state`);
    }
  });
  
  return errors;
}
```

### Rate Limiting

Implement client-side rate limiting:

```javascript theme={null}
class RateLimiter {
  constructor(maxRequests, windowMs) {
    this.maxRequests = maxRequests;
    this.windowMs = windowMs;
    this.requests = [];
  }

  async throttle() {
    const now = Date.now();
    
    // Remove old requests outside window
    this.requests = this.requests.filter(
      time => now - time < this.windowMs
    );
    
    // Check if at limit
    if (this.requests.length >= this.maxRequests) {
      const oldestRequest = this.requests[0];
      const waitTime = this.windowMs - (now - oldestRequest);
      await new Promise(resolve => setTimeout(resolve, waitTime));
      return this.throttle();
    }
    
    // Add this request
    this.requests.push(now);
  }
}

// Usage
const limiter = new RateLimiter(100, 60000); // 100 per minute

async function callAPI(endpoint, data) {
  await limiter.throttle();
  return fetch(endpoint, data);
}
```

## iframe Security

### Sandbox Attribute

Use restrictive sandbox permissions:

```html theme={null}
<iframe
  src="https://shop.usesticker.com/embedded/{partner_id}?session_key=..."
  sandbox="allow-same-origin allow-scripts allow-forms allow-popups allow-popups-to-escape-sandbox allow-top-navigation-by-user-activation"
  allow="payment; publickey-credentials-get; fullscreen"
/>
```

**Required permissions:**

* `allow-same-origin` - Required for authentication cookies
* `allow-scripts` - Required for functionality
* `allow-forms` - Required for search and checkout
* `allow-popups` - Required for payment windows
* `allow-popups-to-escape-sandbox` - Required for Stripe
* `allow-top-navigation-by-user-activation` - Required for redirects

**Avoid unless necessary:**

* `allow-top-navigation` (without user activation) - Can redirect parent unexpectedly
* `allow-modals` - Can show alerts in parent

### Content Security Policy

Configure CSP headers to allow Sticker iframe:

```
Content-Security-Policy:
  default-src 'self';
  frame-src https://shop.usesticker.com https://*.usesticker.com;
  connect-src 'self' https://api.usesticker.com;
```

## Session Token Security

### Token Properties

Session tokens are designed with security in mind:

| Property          | Description                                   |
| ----------------- | --------------------------------------------- |
| **Single-use**    | Invalidated after first authentication        |
| **Short-lived**   | Expire after 5 minutes                        |
| **Cryptographic** | 64-character random hex (256 bits of entropy) |
| **User-bound**    | Tied to specific user profile                 |
| **Partner-bound** | Only valid for your partner iframe URL        |

### Token Transmission

Safely pass tokens to iframe:

```javascript theme={null}
// Good - token in URL parameter (over HTTPS)
const iframeSrc = `https://shop.usesticker.com/embedded/${partnerId}?session_key=${token}`;

// Bad - never put in localStorage accessible to other scripts
localStorage.setItem('sticker_token', token); // ❌
```

### Token Lifecycle

```javascript theme={null}
// Generate fresh token for each session
async function openSuppliesModule(userId) {
  // 1. Generate new token
  const { session_key, iframe_embed_url, expires_at } = await handshake(userId);
  
  // 2. Use immediately (don't store)
  renderIframe(iframe_embed_url);
  
  // 3. Token is consumed on first use
  // 4. If user closes and reopens, generate new token
}
```

## Data Security

### PII Handling

Only send necessary data to Sticker:

```javascript theme={null}
function prepareUserData(user) {
  // Only send necessary fields
  return {
    firstName: user.firstName,
    lastName: user.lastName,
    email: user.email,
    phoneNumber: user.phone  // Optional
    // Don't send: SSN, DOB, medical records, passwords, etc.
  };
}
```

### Data Encryption

All data is protected:

* ✅ All API calls over HTTPS (TLS 1.3)
* ✅ Data encrypted at rest
* ✅ Session tokens are cryptographically random
* ✅ No passwords stored or transmitted

## Security Monitoring

### Log Security Events

Track security-relevant events:

```javascript theme={null}
function logSecurityEvent(event, severity, details) {
  const securityLog = {
    timestamp: new Date().toISOString(),
    event: event,
    severity: severity,
    details: details
  };
  
  // Send to your logging system
  logger.log(securityLog);
  
  // Alert on critical events
  if (severity === 'critical') {
    alertSecurityTeam(securityLog);
  }
}

// Example usage
logSecurityEvent('api_key_exposed', 'critical', {
  message: 'API key found in client-side code',
  file: 'app.js'
});
```

### Monitor for Anomalies

Detect suspicious activity:

```javascript theme={null}
class AnomalyDetector {
  trackRequest(userId, success) {
    // Track error rates per user
    const userErrors = this.getErrorCount(userId);
    
    if (!success) {
      this.incrementErrorCount(userId);
      
      // Alert on high error rate
      if (userErrors > 10) {
        this.alert('High error rate', { userId, errors: userErrors });
      }
    }
  }
}
```

## Incident Response

### If API Key is Compromised

1. **Contact Sticker immediately**
   * Email: [suyash@usesticker.com](mailto:suyash@usesticker.com)
   * Subject line: "URGENT - API Key Compromise"

2. **We will revoke the key** immediately

3. **We'll issue a new key** within minutes

4. **Update your systems** with the new key

5. **Review logs** for any unauthorized access

### Emergency Contacts

* **Partner Support:** [suyash@usesticker.com](mailto:suyash@usesticker.com)
* **Schedule Call:** calendly.com/usesticker/meeting

## Security Checklist

<Steps>
  <Step title="API Keys">
    * [ ] Keys stored in environment variables/secrets manager
    * [ ] No keys in source code or version control
    * [ ] Different keys for sandbox and production
    * [ ] Access limited to backend services only
  </Step>

  <Step title="Requests">
    * [ ] All requests over HTTPS
    * [ ] Input validation before API calls
    * [ ] Rate limiting implemented
    * [ ] Error messages don't leak sensitive data
  </Step>

  <Step title="iframe">
    * [ ] Sandbox attribute configured correctly
    * [ ] CSP headers allow Sticker domains
    * [ ] HTTPS required for parent page
  </Step>

  <Step title="Sessions">
    * [ ] Fresh token generated for each session
    * [ ] Tokens never cached or stored
    * [ ] Expired/failed tokens handled gracefully
  </Step>

  <Step title="Monitoring">
    * [ ] Security events logged
    * [ ] Anomaly detection active
    * [ ] Incident response plan documented
  </Step>
</Steps>

## Resources

<CardGroup cols={2}>
  <Card title="Partner Support" icon="headset" href="mailto:suyash@usesticker.com">
    Get help with security questions
  </Card>

  <Card title="Report Vulnerability" icon="bug" href="mailto:suyash@usesticker.com">
    Responsible disclosure
  </Card>
</CardGroup>
