eetr-auth
Features

OAuth 2.1 & grants

Supported grant types and how the Authorization Code, Client Credentials, and Refresh Token flows behave.

Supported grant types

Grant typeDescription
Authorization Code + PKCE (S256)Primary flow for user-facing apps. PKCE is mandatory.
Client CredentialsMachine-to-machine access. Scoped to registered clients.
Refresh TokenSilent token renewal with rotation on each use.

OAuth 2.1 posture

Authorization Code without PKCE is not supported — this is intentional per OAuth 2.1. Only S256 code challenges are accepted; plain is rejected.

Authorization Code + PKCE

The primary flow for user-facing apps. The client sends a code_challenge at /api/authorize; the user authenticates; the server issues a single-use authorization code bound to the challenge and the exact redirect URI. At /api/token, the client proves possession with the code_verifier.

  • Authorization codes are single-use and short-lived, with PKCE verifier validation (S256 only) and exact-match redirect URI validation.
  • When the openid scope is granted, the token response also includes a signed id_token.
  • Pass a resource parameter to bind the token's audience — see resource indicators.

Consent is recorded: when an authorization succeeds, the scopes actually granted are stored against the (user, client) pair, accumulating across authorizations. What that record drives today is the wording of the screen, not whether it appears.

  • The consent screen is shown on every authorization by a normal user. Skipping it when everything was already consented to is disabled for now: it also removed the only step offering "sign in with a different account", leaving a signed-in user no way to switch. prompt=consent is a no-op while that is the case.
  • The one exception is a synthetic test user on a test client, which goes straight through — the consent row is still recorded. Any other user on a test client sees the screen.
  • If the request adds a scope the user has not seen before, the screen lists only the new scopes — not everything already agreed to.
  • A request with no scope means "everything this client is granted", and the screen lists that resolved set rather than a vague catch-all.

Scopes are described to the user with the consent copy configured on each scope.

Revoking consent

Admins can list and withdraw a user's consents from Dashboard → Users (the user side panel) or via GET / DELETE /api/admin/users/{id}/consents — see the admin surface. Revoking also revokes that user's refresh tokens, access tokens, and unused authorization codes for the client, so access stops immediately rather than at token expiry.

Client Credentials

Machine-to-machine access for backend services. The client authenticates with its client_id and client_secret and receives an access token scoped to its grants.

Public clients can't use client_credentials

A public (PKCE-only) client with token_endpoint_auth_method: none has no secret, so client_credentials is rejected for it. See Clients.

Refresh Token (rotation)

Refresh tokens are long-lived but single-use with rotation — each refresh invalidates the old token and issues a new pair.

  • Revocable (the full token plus its associated refresh chain).
  • Scope is preserved through rotation.
  • User environment access is re-checked on every refresh: revoking a user's access to a client's environment stops new tokens immediately rather than at the refresh token's natural expiry.

Next

On this page