Skip to content

API Authentication quickstart

Add secure authentication to your APIs

Learn how to add authentication to your APIs in minutes. This guide shows you how to:

  • Register API clients that need to access your services
  • Set up OAuth 2.0 authentication using client credentials
  • Validate access tokens to ensure only authorized clients can call your APIs

Who is this for? This guide is for developers who want to secure their APIs and control which external systems can access them.

Prerequisites:

  • A Scalekit account (sign up here if you don’t have one)
  • Basic understanding of REST APIs
  • Familiarity with OAuth 2.0 (optional)

npm install @scalekit-sdk/node

  1. Before an application can access your API, you need to register it as a client. This creates secure credentials that the app developers will use to authenticate its API requests.

    When you register a client, you’ll receive a unique client ID and secret - similar to a username and password for applications. Present it to your API client developers to use in their code.

    POST /organizations/{organization_id}/clients
    # For authentication details, see: http://docs.scalekit.com/apis#description/authentication
    curl -L 'https://<SCALEKIT_ENVIRONMENT_URL>/api/v1/organizations/<ORGANIZATION_ID>/clients' \
    -H 'Content-Type: application/json' \
    -H 'Authorization: Bearer <SCALEKIT_ACCESS_TOKEN>' \
    -d '{
    "name": "GitHub Actions Deployment Service",
    "description": "Service account for GitHub Actions to deploy applications to production",
    "custom_claims": [
    {
    "key": "github_repository",
    "value": "acmecorp/inventory-service"
    },
    {
    "key": "environment",
    "value": "production_us"
    }
    ],
    "scopes": [
    "deploy:applications",
    "read:deployments"
    ],
    "audience": [
    "deployment-api.acmecorp.com"
    ],
    "expiry": 3600
    }'
    API client registration parameters
    ParameterTypeDescription
    name
    string
    A descriptive name for the API client (e.g., “GitHub Actions Deployment Service”)
    description
    string
    A detailed explanation of the client’s purpose and usage
    custom_claims
    array
    Key-value pairs that provide additional context about the client. Each claim must have a key and value field
    scopes
    array
    List of permissions the client needs (e.g., [“deploy:applications”, “read:deployments”])
    audience
    array
    List of API endpoints this client will access (e.g., [“deployment-api.acmecorp.com”])
    expiry
    number
    Token expiration time in seconds. Defaults to 3600 (1 hour)

    The API response contains the client details, including the client_id and client_secret.

    Register an API client API response
    {
    "client": {
    "client_id": "m2morg_68315758685323697",
    "secrets": [
    {
    "id": "sks_68315758802764209",
    "create_time": "2025-04-16T06:56:05.360Z",
    "update_time": "2025-04-16T06:56:05.367190455Z",
    "secret_suffix": "UZ0X",
    "status": "ACTIVE",
    "last_used_time": "2025-04-16T06:56:05.360Z"
    }
    ],
    "name": "GitHub Actions Deployment Service",
    "description": "Service account for GitHub Actions to deploy applications to production",
    "organization_id": "org_59615193906282635",
    "create_time": "2025-04-16T06:56:05.290Z",
    "update_time": "2025-04-16T06:56:05.292145150Z",
    "scopes": [
    "deploy:applications",
    "read:deployments"
    ],
    "audience": [
    "deployment-api.acmecorp.com"
    ],
    "custom_claims": [
    {
    "key": "github_repository",
    "value": "acmecorp/inventory-service"
    },
    {
    "key": "environment",
    "value": "production_us"
    }
    ]
    },
    "plain_secret": "test_ly8G57h0ErRJSObJI6dShkoaq6bigo11Dxcfa6reKG1kKNVbqBKW4H5Ctmb5UZ0X"
    }
  2. After registration, the API client authenticates with your Scalekit environment using its client_id and client_secret (the plain_secret obtained earlier) to request an access token. This process uses the OAuth 2.0 client credentials grant type.

    The client sends a POST request to the /oauth/token endpoint:

    POST /oauth/token
    curl -X POST \
    "https://<SCALEKIT_ENVIRONMENT_URL>/oauth/token" \
    -H "Content-Type: application/x-www-form-urlencoded" \
    -d "grant_type=client_credentials" \
    -d "client_id=<API_CLIENT_ID>" \
    -d "client_secret=<API_CLIENT_SECRET>" \

    Upon successful authentication, Scalekit issues a JWT access token.

    Access token response
    {
    "access_token":"<API_CLIENT_JWT_ACCESS_TOKEN>",
    "token_type":"Bearer",
    "expires_in":86399,
    // Same scopes that were granted during client registration
    "scope":"deploy:applications read:deployments"
    }

    The client includes this access token in the Authorization header of subsequent requests to your API server.

  3. Your API server must validate the incoming JWT access token to ensure the request originates from a trusted API client and that the token is legitimate.

    Validate the token in two steps:

    1. Retrieve the public key: Fetch the appropriate public key from your Scalekit environment’s JSON Web Key Set (JWKS) endpoint. Use the kid (Key ID) from the JWT header to identify the correct key. Cache the key according to standard JWKS practices.

      import jwksClient from 'jwks-rsa';
      const client = jwksClient({
      jwksUri: 'YOUR_JWKS_URI',
      cache: true
      });
      async function getPublicKey(header: any): Promise<string> {
      return new Promise((resolve, reject) => {
      client.getSigningKey(header.kid, (err, key) => {
      if (err) reject(err);
      else resolve(key.getPublicKey());
      });
      });
      }
    2. Verify the token signature: Use the retrieved public key and a JWT library to verify the token’s signature and claims (like issuer, audience, and expiration).

      import jwt from 'jsonwebtoken';
      async function verifyToken(token: string, publicKey: string) {
      try {
      const decoded = jwt.decode(token, { complete: true });
      const verified = jwt.verify(token, publicKey, {
      algorithms: ['RS256'],
      complete: true
      });
      return verified.payload;
      } catch (error) {
      throw new Error('Token verification failed');
      }
      }

    Find complete code examples in the Scalekit M2M Gists repository.

    If the token verification succeeds, your API server can trust the request’s authenticity and proceed with processing it based on the permissions (scopes) encoded within the token.