OAuth Integration Guide
How third-party apps integrate with the Brain OAuth 2.0 server: register a client, obtain user consent, exchange an authorization code for tokens, and call userinfo.
Architecture: core vs example wiring
shared/oauth-wrapper is provider-agnostic OAuth 2.0 logic. oauth-wrapper handles sessions, login orchestration, and storage; you integrate upstream systems via OAuthUserAdapterInterface. This site runs one reference adapter (BrainUserAdapter)—that is not a protocol limitation.
This example: demo-oauth + Brain User
End users sign in with email/password via POST /api/oauth/verify (DemoAuthService → BrainUserAdapter). Authorize and token endpoints are provider-agnostic. See .env.template for OAUTH_WRAPPER_API_BASE and secrets. To swap providers, change oauth-wrapper and IOC bindings.
Overview
This server implements the OAuth 2.0 authorization code grant (RFC 6749) for confidential and public clients (PKCE required for public). Access tokens are issued by Brain; this service handles authorization, token exchange, and userinfo proxying.
Authorization code flow
- Create an app in the developer console and register redirect_uri values (HTTPS required except localhost).
- Redirect the user to GET /oauth/authorize with client_id, redirect_uri, response_type=code; public clients must include PKCE parameters.
- After sign-in and consent, the browser returns to redirect_uri with ?code=...&state=....
- Your backend calls POST /oauth/token with the code to obtain access_token (and optional refresh_token).
- Call GET /userinfo with Bearer access_token to load the user profile.
Endpoints
| Method | Path | Role | Notes |
|---|---|---|---|
| POST | /api/oauth/verify | End-user sign-in (server) | Email/password sign-in for the consent UI session; demo-oauth orchestration—not for OAuth clients. |
| GET | /oauth/authorize | Authorize (browser) | Consent UI; unauthenticated users are sent to login then returned here. |
| POST | /oauth/token | Token (server) | grant_type=authorization_code or refresh_token; client auth via Basic or form body. |
| GET | /userinfo | Userinfo (server) | Requires Authorization: Bearer; returns sub, email, name, and related claims. |
Token exchange
Exchange authorization code
POST /oauth/token
Content-Type: application/x-www-form-urlencoded
grant_type=authorization_code
&code=AUTH_CODE
&redirect_uri=https%3A%2F%2Fapp.example%2Fcallback
&client_id=YOUR_CLIENT_ID
&client_secret=YOUR_CLIENT_SECRET
&code_verifier=VERIFIERRefresh token
POST /oauth/token
Content-Type: application/x-www-form-urlencoded
grant_type=refresh_token
&refresh_token=REFRESH_TOKEN
&client_id=YOUR_CLIENT_ID
&client_secret=YOUR_CLIENT_SECRET// 200 OK { "access_token": "...", "token_type": "Bearer", "expires_in": 3600, "refresh_token": "...", "scope": "openid profile" }
PKCE (public clients)
Generate code_verifier before authorize, pass its S256 digest as code_challenge, then send code_verifier when exchanging the code. Confidential clients may omit PKCE.
Userinfo
Success returns JSON with sub (user id), email, name, and optional roles. Invalid or expired tokens yield 401 with error=invalid_token.
GET /userinfo
Authorization: Bearer ACCESS_TOKENError responses
Authorization errors redirect with error and error_description query params; token and userinfo errors are JSON (e.g. invalid_request, invalid_grant, invalid_client, invalid_token).