Skip to content

User Access Token Authentication

Why

Some endpoints need to know who is making the request — for example to return user-specific data or to enforce permissions. The Registration Backend verifies JWT access tokens issued by the Statista SSO (Auth0) to identify the calling user.

This is separate from API key authentication (x-api-key), which authenticates the client application. A request may require both.

How to Protect a Route

Call validateUserAccessToken(request) in any loader or action. It returns the authenticated user's payload or throws an error response automatically (401 for bad tokens, 500 if the SSO config can't be fetched):

import { validateUserAccessToken } from "../services/validate-user-access-token.server.js";

export async function loader({ request }: Route.LoaderArgs) {
  const user = await validateUserAccessToken(request);

  // user.userId       — Auth0 user ID (e.g. "auth0|6398304")
  // user.legacyUserId — Statista legacy user ID
  // user.permissions  — Array of granted permissions

  return success({ ... });
}

No try/catch needed — auth errors are handled for you.

What the Client Needs to Send

The client must include the JWT access token (not the session blob) in the x-access-token header:

x-access-token: Bearer eyJhbGciOiJSUzI1Ni...

The token must be issued by the same environment you're targeting (e.g. a token from https://statista.com won't work against https://stage.statista.com).

Available User Fields

The most commonly used fields from the decoded token:

Field Description
userId Auth0 user ID (e.g. auth0\|6398304)
legacyUserId Statista legacy user ID

The full schema is defined in app/services/validate-user-access-token.server.ts as UserPayloadSchema.

Local Development

Set SKIP_USER_AUTH=true in your .env to bypass token verification. The function will return a mock user payload without contacting the SSO server, so you don't need a real token during local development.

OpenAPI

When registering a protected route in OpenAPI, add the bearerAuth security scheme and include the 401 and 500 error responses that validateUserAccessToken can throw:

import { ErrorResponseSchema } from "../helpers/api-response.js";

registry.registerPath({
  method: "get",
  path: "/my-endpoint",
  security: [{ bearerAuth: [] }],
  responses: {
    200: { ... },
    401: {
      description: "Missing, malformed, or invalid access token",
      content: {
        "application/json": { schema: ErrorResponseSchema },
      },
    },
    500: {
      description: "Failed to fetch SSO config",
      content: {
        "application/json": { schema: ErrorResponseSchema },
      },
    },
  },
});