Skip to content
Talk to an Engineer Dashboard

API keys

Issue long-lived, revocable API keys scoped to organizations and users for programmatic access to your APIs

When your customers integrate with your APIs — whether for CI/CD pipelines, partner integrations, or internal tooling — they need a straightforward way to authenticate. Scalekit API keys give you long-lived, revocable bearer credentials for organization-level or user-level access to your APIs.

In this guide, you’ll learn how to create, validate, list, and revoke API keys using the Scalekit.

Customer's App (API Client)UserYour AppScalekit Request API key Create token (organizationId, userId?) API key + tokenId API key Configure API key Request with Authorization header Validate token Organization ID (+ User ID if user-scoped) Filter data by org and user context Response
  1. npm install @scalekit-sdk/node

    Initialize the Scalekit client with your environment credentials:

    Express.js
    2 collapsed lines
    import { ScalekitClient } from '@scalekit-sdk/node';
    const scalekit = new ScalekitClient(
    process.env.SCALEKIT_ENVIRONMENT_URL,
    process.env.SCALEKIT_CLIENT_ID,
    process.env.SCALEKIT_CLIENT_SECRET
    );
  2. To get started, create an API key scoped to an organization. You can optionally scope it to a specific user and attach custom metadata.

    When to use: Organization-scoped keys are for customers who need full access to all resources within their workspace or account. When they authenticate with the key, Scalekit validates it and confirms the organization context — your API then exposes all resources they own.

    Example scenario: You’re building a CRM like HubSpot. Your customer integrates with your API using an organization-scoped key. When they request contacts, tasks, or deals, the key validates successfully for their organization, and your API returns all resources in that workspace.

    This is the most common pattern for service-to-service integrations where the API key represents access on behalf of an entire organization.

    try {
    const response = await scalekit.token.createToken(organizationId, {
    description: 'CI/CD pipeline token',
    });
    // Store securely — this value cannot be retrieved again after creation
    const opaqueToken = response.token;
    // Stable identifier for management operations (format: apit_xxxxx)
    const tokenId = response.tokenId;
    } catch (error) {
    console.error('Failed to create token:', error.message);
    }

    When to use: User-scoped keys enable fine-grained data filtering based on who owns the key. Your API validates the key, receives the user context, and then exposes only data relevant to that user — enabling role-based filtering without additional database lookups.

    Example scenario: Your CRM has a /tasks endpoint. One customer gives their team member a user-scoped API key. When that person calls /tasks, the key validates for their organization and user, and your API returns only tasks assigned to them — not all tasks in the workspace. Another team member with a different key sees only their own tasks.

    User-scoped keys enable personal access tokens, per-user audit trails, and user-level rate limiting. You can also attach custom claims as key-value metadata.

    try {
    const userToken = await scalekit.token.createToken(organizationId, {
    userId: 'usr_12345',
    customClaims: {
    team: 'engineering',
    environment: 'production',
    },
    description: 'Deployment service token',
    });
    const opaqueToken = userToken.token;
    const tokenId = userToken.tokenId;
    } catch (error) {
    console.error('Failed to create token:', error.message);
    }

    The response contains three fields:

    FieldDescription
    tokenThe API key string. Returned only at creation.
    token_idAn identifier (format: apit_xxxxx) for referencing the token in management operations.
    token_infoMetadata including organization, user, custom claims, and timestamps.
  3. When your API server receives a request with an API key, you’ll want to verify it’s legitimate before processing the request. Pass the key to Scalekit — it validates the key server-side and returns the associated organization, user, and metadata context.

    import { ScalekitValidateTokenFailureException } from '@scalekit-sdk/node';
    try {
    const result = await scalekit.token.validateToken(opaqueToken);
    const orgId = result.tokenInfo?.organizationId;
    const userId = result.tokenInfo?.userId;
    const claims = result.tokenInfo?.customClaims;
    } catch (error) {
    if (error instanceof ScalekitValidateTokenFailureException) {
    // Token is invalid, expired, or revoked
    console.error('Token validation failed:', error.message);
    }
    }

    If the API key is invalid, expired, or has been revoked, validation fails with a specific error that you can catch and handle in your code. This makes it easy to reject unauthorized requests in your API middleware.

    Beyond the basic organization and user information, the validation response also includes any roles assigned to the user and external identifiers you’ve configured for the organization. These are useful for making authorization decisions without additional database lookups.

    try {
    const result = await scalekit.token.validateToken(opaqueToken);
    // Roles assigned to the user
    const roles = result.tokenInfo?.roles;
    // External identifiers for mapping to your system
    const externalOrgId = result.tokenInfo?.organizationExternalId;
    const externalUserId = result.tokenInfo?.userExternalId;
    } catch (error) {
    if (error instanceof ScalekitValidateTokenFailureException) {
    console.error('Token validation failed:', error.message);
    }
    }

    If you attached custom claims when creating the API key, they come back in every validation response. This is a convenient way to make fine-grained authorization decisions — like restricting access by team or environment — without hitting your database.

    try {
    const result = await scalekit.token.validateToken(opaqueToken);
    const team = result.tokenInfo?.customClaims?.team;
    const environment = result.tokenInfo?.customClaims?.environment;
    // Use metadata for authorization
    if (environment !== 'production') {
    return res.status(403).json({ error: 'Production access required' });
    }
    } catch (error) {
    if (error instanceof ScalekitValidateTokenFailureException) {
    console.error('Token validation failed:', error.message);
    }
    }
  4. You can retrieve all active API keys for an organization at any time. The response supports pagination for large result sets, and you can filter by user to find keys scoped to a specific person.

    try {
    // List tokens for an organization
    const response = await scalekit.token.listTokens(organizationId, {
    pageSize: 10,
    });
    for (const token of response.tokens) {
    console.log(token.tokenId, token.description);
    }
    // Paginate through results
    if (response.nextPageToken) {
    const nextPage = await scalekit.token.listTokens(organizationId, {
    pageSize: 10,
    pageToken: response.nextPageToken,
    });
    }
    // Filter tokens by user
    const userTokens = await scalekit.token.listTokens(organizationId, {
    userId: 'usr_12345',
    });
    } catch (error) {
    console.error('Failed to list tokens:', error.message);
    }

    The response includes totalCount for the total number of matching tokens and nextPageToken / prevPageToken cursors for navigating pages.

  5. When you need to revoke an API key — for example, when an employee leaves or you suspect credentials have been compromised — you can invalidate it through Scalekit. Revocation takes effect instantly: the very next validation request for that key will fail.

    This operation is idempotent, so calling invalidate on an already-revoked key succeeds without error.

    try {
    // Invalidate by API key string
    await scalekit.token.invalidateToken(opaqueToken);
    // Or invalidate by token_id (useful when you store tokenId for lifecycle management)
    await scalekit.token.invalidateToken(tokenId);
    } catch (error) {
    console.error('Failed to invalidate token:', error.message);
    }
  6. Now let’s put it all together. The most common pattern is to add API key validation as middleware in your API server. Extract the Bearer token from the Authorization header, validate it through Scalekit, and use the returned context for authorization decisions.

    Express.js
    import { ScalekitValidateTokenFailureException } from '@scalekit-sdk/node';
    async function authenticateToken(req, res, next) {
    const authHeader = req.headers['authorization'];
    const token = authHeader && authHeader.split(' ')[1];
    if (!token) {
    // Reject requests without credentials to prevent unauthorized access
    return res.status(401).json({ error: 'Missing authorization token' });
    }
    try {
    // Server-side validation — Scalekit checks token status in real time
    const result = await scalekit.token.validateToken(token);
    // Attach token context to the request for downstream handlers
    req.tokenInfo = result.tokenInfo;
    next();
    } catch (error) {
    if (error instanceof ScalekitValidateTokenFailureException) {
    // Revoked, expired, or malformed tokens are rejected immediately
    return res.status(401).json({ error: 'Invalid or expired token' });
    }
    throw error;
    }
    }
    // Apply to protected routes
    app.get('/api/resources', authenticateToken, (req, res) => {
    const orgId = req.tokenInfo.organizationId;
    // Serve resources scoped to this organization
    });

    Using validation context for data filtering

    Section titled “Using validation context for data filtering”

    After validation succeeds, your middleware has access to the organization and (optionally) user context. Use this context to filter the data your endpoint returns — no additional database queries needed.

    For organization-scoped keys: Extract the organization ID from the validation response. Your endpoint then returns resources belonging to that organization. If a customer authenticates with an organization-scoped key, they get access to all their workspace data.

    For user-scoped keys: Extract both organization ID and user ID. Filter your query to return only resources belonging to that user within the organization. If a team member authenticates with a user-scoped key, they see only their assigned tasks, their owned projects, or their allocated resources — depending on your application logic.

    The validation response is your source of truth. Trust the organization and user context it provides, and use it to build your authorization queries without additional lookups.

    Here are a few tips to help you get the most out of API keys in production:

    • Store API keys securely: Treat API keys like passwords. Store them in encrypted secrets managers or environment variables. Never log keys, commit them to version control, or expose them in client-side code.
    • Set expiry for time-limited access: Use the expiry parameter for keys that should automatically become invalid after a set period. This limits the blast radius if a key is compromised.
    • Use custom claims for context: Attach metadata like team, environment, or service as custom claims. Your API middleware can use these claims for fine-grained authorization without additional database lookups.
    • Rotate keys safely: To rotate an API key, create a new key, update the consuming service to use the new key, verify the new key works, then invalidate the old key. This avoids downtime during rotation.

    You now have everything you need to issue, validate, and manage API keys in your application.