OAuth reference

How the data and the API work, and why.

What the MangaBaka OAuth provider supports, how long its tokens live, and the behaviour most likely to trip up a client.

For a walkthrough, see Let users sign in with OAuth. The machine-readable version is the discovery document.

Read this first#↑

  • Always request openid. The API checks every bearer token against the userinfo endpoint, which requires openid. A token without it gets 401 on every endpoint, whatever other scopes it has.
  • PKCE is required for every client, Web apps with a secret included. Only S256.
  • Store the new refresh token on every refresh. Sending a retired one revokes every token your app holds for that user.
  • redirect_uri must match exactly, in the authorize request and again in the token request. An extra / or query string is rejected.
  • OAuth tokens go in Authorization: Bearer. Personal access tokens go in x-api-key. Swapping them gets 401, and sending both gets 400.
  • Client credentials tokens don't work with the API. They have no user, and the API needs one.

Endpoints#↑

All under https://mangabaka.org. Issuer: https://mangabaka.org/auth.

Endpoint URL
Authorize /auth/oauth2/authorize
Token /auth/oauth2/token
Userinfo /auth/oauth2/userinfo
Revoke /auth/oauth2/revoke
Introspect /auth/oauth2/introspect
Signing keys /auth/jwks

The API itself is on https://api.mangabaka.org.

What's supported#↑

Feature Supported
Grant types authorization_code, refresh_token
Response type and mode code, returned in the query string
PKCE S256, required
Client authentication Web apps: client_secret_basic or client_secret_post. Public apps: client_id only
prompt login, consent, none
Access tokens Opaque strings. Not JWTs, so don't try to decode them
ID tokens JWT signed with EdDSA, keys at /auth/jwks
Scopes See OAuth scopes

Token lifetimes#↑

Token Lifetime
Authorization code 10 minutes
Access token 7 days
Access token that includes mod 1 day
Refresh token 365 days, counted again from each refresh
ID token 10 hours

expires_in in the token response is the access token's lifetime in seconds.

Refresh tokens#↑

  • You only get one if you ask for offline_access.
  • Each refresh returns a new refresh token and retires the old one.
  • You can ask for fewer scopes on refresh by sending scope, never more. Drop offline_access and the next response has no refresh token.
  • A user who has approved your app isn't asked again while you request the same scopes or fewer.
  • Approving a new set of scopes replaces the old set, it doesn't add to it. Request everything you need in one go.
  • Users approve all requested scopes or none.
  • prompt=none returns login_required or consent_required to your redirect_uri instead of showing a page.

Redirects#↑

  • Success: code, state and iss in the query. Check that iss is https://mangabaka.org/auth.
  • Errors: error, error_description, state and iss. A user who declines gets access_denied.
  • If the client_id or redirect_uri is wrong, the user lands on a MangaBaka error page instead, since there is no safe place to send them.
  • Plain http redirect URLs are only accepted for localhost, 127.0.0.1 and [::1].
  • For 127.0.0.1 and [::1], any port matches the registered URL, so a native app can pick a free port at runtime. localhost must match the port exactly.

User identity#↑

Call the userinfo endpoint with the access token. It returns:

  • sub: the user's id. This is the user_id other endpoints use.
  • preferred_username, nickname, name and picture.
  • badges, with the badges scope.

There is no email. The ID token carries little beyond sub, so use userinfo for profile data.

Revoking and inspecting tokens#↑

  • Revoke takes token, token_type_hint (access_token or refresh_token) and client_id, plus the secret for Web apps.
  • Introspect needs the client secret, so it only works for Web apps, and only for tokens issued to that app.

Not available#↑

  • Dynamic client registration. Register apps under New application.
  • The end-session (logout) endpoint. Revoke the refresh token instead.
  • Resource indicators (resource). The token endpoint answers 400 invalid_target.