Skip to content

API Authentication ​

How to authenticate with the Scry API.

Overview ​

The Upload Service uses API key authentication. API keys are:

  • Bound to a single project
  • Hashed before storage (never stored in plain text)
  • Revocable at any time

API Key Format ​

scry_proj_{projectId}_{randomString}

Components:

PartDescription
scry_proj_Fixed prefix (10 chars)
{projectId}Your project ID (variable)
_Separator
{randomString}Random base64url (32 chars)

Example:

scry_proj_my-design-system_KjE2MzQ1Njc4OTBhYmNkZWYxMjM0

Using API Keys ​

HTTP Header ​

Include the API key in the X-API-Key header:

bash
curl -X POST \
  -H "X-API-Key: scry_proj_my-project_xxx" \
  -H "Content-Type: application/zip" \
  --data-binary @storybook.zip \
  https://upload.scrymore.com/upload/my-project/v1.0.0

Environment Variable ​

Set as environment variable for CLI:

bash
export STORYBOOK_DEPLOYER_API_KEY=scry_proj_my-project_xxx
# or
export SCRY_API_KEY=scry_proj_my-project_xxx

npx @scrymore/scry-deployer --dir ./storybook-static

GitHub Actions Secret ​

  1. Add as repository secret:

    • Settings → Secrets → Actions → New secret
    • Name: SCRY_API_KEY
    • Value: Your API key
  2. Use in workflow:

yaml
- name: Deploy
  env:
    STORYBOOK_DEPLOYER_API_KEY: ${{ secrets.SCRY_API_KEY }}
  run: npx @scrymore/scry-deployer --dir ./storybook-static

Getting API Keys ​

Via Dashboard ​

  1. Log in to dashboard.scrymore.com
  2. Select your project
  3. Go to Settings → API Keys
  4. Click Generate New Key
  5. Copy immediately (shown once!)

Self-Hosted ​

For self-hosted instances, create keys via Firebase Console or using the key generation script:

javascript
const crypto = require('crypto');
const projectId = 'my-project';
const randomPart = crypto.randomBytes(32).toString('base64url');
const rawKey = `scry_proj_${projectId}_${randomPart}`;
const hash = crypto.createHash('sha256').update(rawKey).digest('hex');

console.log('Raw Key:', rawKey);
console.log('Hash:', hash);
console.log('Prefix:', rawKey.slice(0, 12));

Error Responses ​

401 Unauthorized ​

Missing header:

json
{
  "error": "Authentication required",
  "message": "Missing X-API-Key header"
}

Invalid format:

json
{
  "error": "Invalid API key format",
  "message": "API key must start with scry_proj_"
}

Invalid key:

json
{
  "error": "Invalid API key",
  "message": "The provided API key is invalid or has been revoked"
}

Expired key:

json
{
  "error": "API key expired",
  "message": "This API key has expired"
}

403 Forbidden ​

Project mismatch:

json
{
  "error": "Project mismatch",
  "message": "The API key does not belong to the requested project"
}

Authentication Flow ​

1. Client sends request with X-API-Key header
           │
           ▼
2. Middleware extracts API key
           │
           ▼
3. Validate format (scry_proj_{project}_{random})
           │
           ▼
4. Extract project ID from key
           │
           ▼
5. Hash key with SHA-256
           │
           ▼
6. Query Firestore for matching hash
           │
           ▼
7. Verify key status (active, not expired)
           │
           ▼
8. Verify project ID matches request
           │
           ▼
9. Update lastUsedAt timestamp
           │
           ▼
10. Allow request to proceed

Security Best Practices ​

Do ​

  • Store keys in environment variables or secret managers
  • Use different keys for different environments
  • Rotate keys periodically (every 90 days)
  • Revoke unused keys immediately
  • Monitor key usage via dashboard

Don't ​

  • Commit keys to version control
  • Share keys across projects
  • Use keys in client-side code
  • Expose keys in logs or error messages

Key Lifecycle ​

Creation ​

  1. User requests new key
  2. System generates random string
  3. Key is displayed once to user
  4. Only SHA-256 hash is stored

Usage ​

  1. Request includes API key
  2. System hashes and validates
  3. lastUsedAt timestamp updated
  4. Request proceeds

Revocation ​

  1. User revokes key in dashboard
  2. Status set to revoked
  3. Future requests immediately rejected

Troubleshooting ​

"Invalid API key format" ​

  • Ensure key starts with scry_proj_
  • Check for extra whitespace
  • Verify no truncation occurred

"Invalid API key" ​

  • Key may have been revoked
  • Key may be for different project
  • Check for typos when copying

"Project mismatch" ​

  • API key is bound to different project
  • Verify project ID in request URL
  • Generate new key for correct project

Next Steps ​