Skip to main content

Backend / Service Track

Use this track when you are protecting a REST or GraphQL API, a background worker, or a service-to-service call. By the end you will be issuing and validating tokens and making authorization decisions from your service.

Prerequisites​

  • A LumoAuth organization — sign up
  • A confidential OAuth client (client ID + client secret). "Confidential" means the client can safely hold a secret — unlike a browser or mobile app — so it is allowed to use client-credential based grants.

1. Learn the model​

2. Get an access token (Client Credentials)​

The client_credentials grant is part of core OAuth 2.0 (the sign-in and token protocol every flow on this site builds on). It issues a token to the service itself, with no end user involved — useful for cron jobs, server-to-server calls, and background workers.

curl -X POST https://app.lumoauth.dev/orgs/YOUR_ORG/api/v1/oauth/token \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=client_credentials" \
-d "client_id=YOUR_CLIENT_ID" \
-d "client_secret=YOUR_CLIENT_SECRET" \
-d "scope=read:users"

The response is a JWT access_token scoped to your app. See the Token Endpoint reference for all supported grants (authorization_code, refresh_token, token-exchange, CIBA, device).

Calling the Admin API from a service?

Pick the narrowest credential. An API key with one resource scope (for example admin:users:read) is the simplest. If you use an OAuth token instead, it must carry admin or admin:<resource>:<read|write>; a plain openid profile email token gets 403. Neither credential ever creates a browser session. See Credentials and access model and Admin API authentication.

3. Validate tokens in your service​

Pick one of two strategies:

StrategyWhen to useEndpoint
Local JWT validationHigh-throughput services; no network hop per request.well-known/jwks.json (JWKS, the list of public keys used to verify tokens)
Token introspectionYou need instant revocation to take effect/oauth/introspect

Local validation means your service fetches the public keys from jwks.json (cached), then verifies the JWT (signed token) signature offline. Introspection means asking LumoAuth on every request whether the token is still valid — slower, but LumoAuth can deny a revoked token immediately.

Whichever you pick, check iss against the issuer in the discovery document (byte-compare), aud against your resource, and exp. The issuer is https://app.lumoauth.dev/orgs/YOUR_ORG/api/v1, or your bare custom domain, and is identical everywhere a token or introspection response is produced.

Why the issuer check matters

The issuer identifier in the response prevents mix-up attacks, where a code or token from one authorization server is presented to a client expecting another. The one thing to do: compare iss with the discovery issuer before trusting anything else in the token. See the standards reference for the specification behind it.

4. Make authorization decisions​

Your service now has an authenticated caller. Decide what they are allowed to do.

5. Production checklist​

Common mistakes​

  • 403 forbidden on /api/v1/admin/... with a valid OAuth token. The token lacks an admin scope. Add admin:<resource>:<read|write> to a first-party client's allowed scopes and request it, or use an API key.
  • 403 insufficient scope with an API key on a POST. The key only has a :read scope for that resource.
  • Expecting a session cookie after an API call. API keys and Bearer tokens are stateless by design; send the credential on every request.
  • Pinning the issuer to an old value. Read issuer from discovery instead of hard-coding it.

Next track​

Standards used on this page​

Plain nameStandard
OAuth 2.0 (the core sign-in and token protocol)RFC 6749
Token introspectionRFC 7662
Issuer identifier in the responseRFC 9207

See the standards reference for what each one covers and how LumoAuth uses it.