AshAuthentication.Oauth2Server.Jwt (ash_authentication_oauth2_server v0.1.0)

Copy Markdown View Source

Mint and verify OAuth 2.1 access tokens.

Uses HS256 with a shared secret resolved through the AshAuthentication.Secret behaviour.

Why this exists alongside AshAuthentication.Jwt

Both modules wrap Joken. They are kept separate because:

  • Audience binding (RFC 8707) — every minted token carries an aud matching the configured resource_url, and verify/2 rejects tokens whose aud doesn't match. AshAuthentication.Jwt's aud is hardcoded to a version constraint and is not customizable per-token.
  • Hot-path verify — the resource server validates a token on every protected request. Verify here is signature + claims only, no user load. The bearer plug controls when the user record is fetched.
  • Decoupling — these tokens identify a user by their primary key (sub), not via an AshAuthentication strategy, so we don't require the user resource to declare authentication.tokens.enabled? true.

Summary

Functions

Mint a new access token.

Verify a token's signature, issuer, audience, expiry, and not-before.

Functions

mint(server, opts)

@spec mint(
  server :: module(),
  keyword()
) :: {:ok, String.t(), map()} | {:error, term()}

Mint a new access token.

Required keys: :sub, :client_id, :scope. Optional: :ttl (seconds, defaults to the server's access_token_lifetime).

verify(server, token)

@spec verify(server :: module(), String.t()) :: {:ok, map()} | {:error, term()}

Verify a token's signature, issuer, audience, expiry, and not-before.

Per RFC 7519 §4.1.4 we allow a small leeway on exp and nbf (the server-configured clock_skew_seconds, default 30s) so tokens minted by an AS whose clock is slightly off from the resource server still verify.

Returns {:ok, claims} on success or {:error, reason} on failure.