Skip to main content

Authentication

The Cat Data API uses Auth0 for secure JWT (JSON Web Token) authentication. All API endpoints except the root health check require a valid JWT token in the request headers.

Overview

Authentication is handled using the RS256 asymmetric algorithm. The API validates tokens by:
  1. Extracting the JWT from the Authorization header
  2. Fetching Auth0’s public keys from the JWKS endpoint
  3. Verifying the token signature using the public key
  4. Validating the token’s audience and issuer claims

Authentication Flow

Required Headers

Every authenticated request must include the Authorization header with a Bearer token:
Authorization: Bearer YOUR_JWT_TOKEN

Example Request

curl http://localhost:3000/api/images \
  -H "Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9..."

Getting an Auth0 Token

To authenticate with the Cat Data API, you need to obtain a JWT token from Auth0. Here’s the general process:
1

Configure Auth0 API

In your Auth0 dashboard:
  1. Create an API (or use an existing one)
  2. Set the API identifier (this becomes your AUTH0_AUDIENCE)
  3. Choose RS256 as the signing algorithm
2

Create an Auth0 Application

Create an application that will request tokens:
  1. Go to Applications in Auth0 dashboard
  2. Create a new application (Machine to Machine, SPA, or Regular Web App)
  3. Authorize the application to access your API
3

Request a Token

Use Auth0’s token endpoint to get a JWT:
curl --request POST \
  --url https://YOUR_DOMAIN.auth0.com/oauth/token \
  --header 'content-type: application/json' \
  --data '{
    "client_id":"YOUR_CLIENT_ID",
    "client_secret":"YOUR_CLIENT_SECRET",
    "audience":"YOUR_API_IDENTIFIER",
    "grant_type":"client_credentials"
  }'
Response:
{
  "access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...",
  "token_type": "Bearer",
  "expires_in": 86400
}
4

Use the Token

Include the access_token in your API requests:
curl http://localhost:3000/api/images \
  -H "Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9..."
Never expose your client_secret in client-side code. For frontend applications, use Auth0’s SPA SDKs with PKCE flow.

JWT Validation Implementation

The API uses the express-jwt and jwks-rsa packages to validate tokens. Here’s the actual middleware code from the Cat Data API:
import { expressjwt } from 'express-jwt';
import jwksRsa from 'jwks-rsa';
import { RequestHandler } from 'express';
import dotenv from 'dotenv';
dotenv.config();

const domain = process.env.AUTH0_DOMAIN; 
const audience = process.env.AUTH0_AUDIENCE; 

export const checkJwt: RequestHandler = expressjwt({
    secret: jwksRsa.expressJwtSecret({
        cache: true,
        rateLimit: true,
        jwksRequestsPerMinute: 5,
        jwksUri: `${domain}.well-known/jwks.json`,
    }),
    audience: audience,
    issuer: `${domain}`,
    algorithms: ['RS256'],
});

Key Configuration Parameters

ParameterValueDescription
cachetrueCaches signing keys to reduce requests to Auth0
rateLimittruePrevents excessive requests to JWKS endpoint
jwksRequestsPerMinute5Maximum JWKS requests per minute
audienceFrom .envExpected audience claim in the token
issuerFrom .envExpected issuer claim (Auth0 domain)
algorithms['RS256']Allowed signing algorithm
The JWKS (JSON Web Key Set) endpoint is automatically constructed by appending .well-known/jwks.json to your Auth0 domain.

Environment Configuration

The authentication middleware requires these environment variables:
AUTH0_DOMAIN=https://your-tenant.auth0.com/
AUTH0_AUDIENCE=your-api-identifier
Important: The AUTH0_DOMAIN must include the trailing slash (/) since the code directly appends .well-known/jwks.json to it.

Token Validation Process

When a request arrives, the checkJwt middleware:
  1. Extracts the token from the Authorization: Bearer header
  2. Decodes the token header to identify which key was used to sign it
  3. Fetches the signing key from Auth0’s JWKS endpoint (or uses cached key)
  4. Verifies the signature using the RS256 algorithm and public key
  5. Validates claims:
    • aud (audience) matches AUTH0_AUDIENCE
    • iss (issuer) matches AUTH0_DOMAIN
    • exp (expiration) is not in the past
  6. Attaches decoded token to req.auth for use in route handlers

Common Authentication Errors

401 Unauthorized - No Token Provided

{
  "code": "credentials_required",
  "message": "No authorization token was found"
}
Cause: The Authorization header is missing from the request. Solution: Include the header with format Authorization: Bearer YOUR_TOKEN

401 Unauthorized - Invalid Token

{
  "code": "invalid_token",
  "message": "jwt malformed"
}
Causes:
  • Token is not properly formatted
  • Token is corrupted or incomplete
Solution: Ensure you’re sending the complete token string from Auth0

401 Unauthorized - Expired Token

{
  "code": "invalid_token",
  "message": "jwt expired"
}
Cause: The token’s exp (expiration) claim is in the past. Solution: Request a new token from Auth0

401 Unauthorized - Invalid Signature

{
  "code": "invalid_token",
  "message": "invalid signature"
}
Causes:
  • Token was signed with a different key
  • Token was manually modified
  • Wrong Auth0 domain configured
Solution: Verify your AUTH0_DOMAIN environment variable matches the token issuer

401 Unauthorized - Invalid Audience

{
  "code": "invalid_token",
  "message": "jwt audience invalid. expected: your-api-identifier"
}
Cause: The token’s aud claim doesn’t match the configured AUTH0_AUDIENCE. Solution: Ensure you’re requesting tokens with the correct audience parameter

401 Unauthorized - Invalid Issuer

{
  "code": "invalid_token",
  "message": "jwt issuer invalid. expected: https://your-tenant.auth0.com/"
}
Cause: The token’s iss claim doesn’t match the configured AUTH0_DOMAIN. Solution: Verify the AUTH0_DOMAIN in your .env file

Testing Authentication

You can test the authentication flow using these approaches:

Using Auth0’s Test Tab

  1. Go to your API in the Auth0 dashboard
  2. Click the “Test” tab
  3. Copy the test token provided
  4. Use it in your API requests

Using Postman

1

Set Up Authorization

In Postman, go to the Authorization tab and select “OAuth 2.0”
2

Configure Token Request

  • Token URL: https://YOUR_DOMAIN.auth0.com/oauth/token
  • Client ID: Your Auth0 application client ID
  • Client Secret: Your Auth0 application client secret
  • Audience: Your API identifier
  • Grant Type: Client Credentials
3

Get Token

Click “Get New Access Token” and Postman will request and store the token
4

Make Request

Use the token in your requests to the Cat Data API

Security Best Practices

Use HTTPS

Always use HTTPS in production to prevent token interception

Short Token Lifetimes

Configure short expiration times (e.g., 24 hours or less)

Secure Storage

Store tokens securely (e.g., httpOnly cookies, secure storage)

Validate Scopes

Implement scope-based authorization for granular permissions
Never commit tokens or credentials to version control. Always use environment variables for sensitive configuration.

Protected Endpoints

All endpoints except / require authentication. Here’s how the middleware is applied in the API:
// Protected: Upload endpoint
app.post('/api/upload', checkJwt, upload.single('file'), async (req, res) => {
  // Handler code
});

// Protected: Delete endpoint
app.delete('/api/image/:id', checkJwt, async (req, res) => {
  // Handler code
});

// Protected: Get single image
app.get('/api/image/:id', checkJwt, async (req, res) => {
  // Handler code
});

// Protected: List all images
app.get('/api/images', checkJwt, async (req, res) => {
  // Handler code
});

// Unprotected: Health check
app.get('/', (req, res) => {
  res.send('Hello from CAT API');
});
The checkJwt middleware is applied to each protected route, ensuring that only authenticated requests can access sensitive operations.

Build docs developers (and LLMs) love