Skip to main content

API authentication for M2M clients

This guide explains how your application can validate API requests from machine-to-machine (M2M) clients using Scalekit's M2M authentication system. This guide explains the authentication flow, from obtaining access tokens to validating requests using JSON Web Key Sets (JWKS).

How M2M clients authenticate with your API

Every Scalekit environment functions as an Authorization Server. M2M clients authenticate using client credentials with this server.

Storing client credentials

M2M clients must securely store their credentials in environment variables:

Environment variables
YOURAPP_ENVIRONMENT_URL="<YOURAPP_SCALEKIT_ENVIRONMENT_URL>"
YOURAPP_CLIENT_ID="<YOURAPP_CLIENT_ID>"
YOURAPP_CLIENT_SECRET="<YOURAPP_CLIENT_SECRET>"

Obtaining access tokens

To authenticate API requests, clients must first obtain an access token from your authorization server using the Token endpoint:

Token endpoint
https://<YOURAPP_SCALEKIT_ENVIRONMENT_URL>/oauth/token

The client sends their credentials to this endpoint:

Token request
curl -X POST \
  "https://<YOURAPP_SCALEKIT_ENVIRONMENT_URL>/oauth/token" \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=client_credentials" \
  -d "client_id=<YOURAPP_CLIENT_ID>" \
  -d "client_secret=<YOURAPP_CLIENT_SECRET>" \
  -d "scope=openid profile email"

The server returns a JSON response containing the access token:

Token response
{
  "access_token": "<YOURAPP_ACCESS_TOKEN>",
  "token_type": "Bearer",
  "expires_in": 86399,
  "scope": "openid"
}
FieldDescription
access_tokenToken for authenticating API requests
token_typeAlways "Bearer" for this flow
expires_inToken validity period in seconds (typically 24 hours)
scopeAuthorized scopes for this token

Using access tokens

After obtaining the access token, clients include it in the Authorization header of their API requests:

API request with access token
curl --request GET "https://<your-api-endpoint>" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer <YOURAPP_ACCESS_TOKEN>"

Validating access tokens

Your API server must validate access tokens before processing requests. Scalekit uses JSON Web Tokens (JWTs) signed with RSA keys, which you validate using the JSON Web Key Set (JWKS) endpoint.

Retrieving JWKS

Your application should fetch the public keys from the JWKS endpoint:

JWKS endpoint
https://<YOURAPP_ENVIRONMENT_URL>/.well-known/jwks.json
JWKS response
{
  "keys": [
    {
      "use": "sig",
      "kty": "RSA",
      "kid": "snk_58327480989122566",
      "alg": "RS256",
      "n": "wUaqIj3pIE_zfGN9u4GySZs862F-0Kl-..",
      "e": "AQAB"
    }
  ]
}

Token validation process

When your API receives a request with a JWT, follow these steps:

  1. Extract the token from the Authorization header
  2. Fetch the JWKS from the endpoint
  3. Use the public key from JWKS to verify the token's signature
  4. Validate the token's claims (issuer, audience, expiration)

This example shows how to fetch JWKS data:

Fetch JWKS with cURL
curl -s "https://<YOURAPP_ENVIRONMENT_URL>/keys" | jq
Token Validation with Node.js
const express = require('express');
const jwt = require('jsonwebtoken');
const jwksClient = require('jwks-rsa');
const app = express();

// Initialize JWKS client
const client = jwksClient({
  jwksUri: `https://<YOURAPP_ENVIRONMENT_URL>/keys`
});

// Function to get signing key
function getKey(header, callback) {
  client.getSigningKey(header.kid, function(err, key) {
    if (err) return callback(err);

    const signingKey = key.publicKey || key.rsaPublicKey;
    callback(null, signingKey);
  });
}

// Middleware to validate JWT
function validateJwt(req, res, next) {
  // Extract token from header
  const authHeader = req.headers.authorization;
  if (!authHeader || !authHeader.startsWith('Bearer ')) {
    return res.status(401).json({ error: 'Missing authorization token' });
  }

  const token = authHeader.split(' ')[1];

  // Verify token
  jwt.verify(token, getKey, {
    algorithms: ['RS256']
  }, (err, decoded) => {
    if (err) {
      return res.status(401).json({ error: 'Invalid token', details: err.message });
    }

    // Add decoded token to request object
    req.user = decoded;
    next();
  });
}

// Apply middleware to protected routes
app.use('/api', validateJwt);

// Example protected route
app.get('/api/data', (req, res) => {
  res.json({ message: 'Authenticated successfully', userId: req.user.sub });
});

app.listen(3000, () => {
  console.log('Server running on port 3000');
});

Security best practices

When implementing token validation:

  1. Always verify the token signature using the public key from JWKS
  2. Validate token expiration and required claims
  3. Consider caching JWKS responses to improve performance
  4. Implement token revocation checks for sensitive operations
  5. Use HTTPS for all API endpoints

SDK support status

Our Python SDK currently includes support for M2M authentication. The support to verify tokens is coming soon to Node, Java, and Go SDKs.


Is this page helpful? Yes No