Authorization Endpoints
Technical reference for the OAuth 2.0 authorization and discovery endpoints.
Authorization endpoint
GET /oauth/authorizeInitiates the OAuth 2.0 Authorization Code flow. Redirects the user to the Loopwise login and consent screen.
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
response_type | string | Yes | Must be code |
client_id | string | Yes | The application's client ID |
redirect_uri | string | Yes | Must exactly match a registered redirect URI |
scope | string | Yes | Space-separated list of requested scopes |
state | string | Recommended | Opaque value to prevent CSRF. Returned unchanged in the callback |
code_challenge | string | Yes | Base64url-encoded SHA-256 hash of the code_verifier |
code_challenge_method | string | Yes | Must be S256 |
school_id | string | No | Pre-select a school by UUID (skips the school picker if valid) |
Success response
Redirects to redirect_uri with:
| Parameter | Description |
|---|---|
code | The authorization code (single-use, short-lived) |
state | The state value from the request |
Error response
Redirects to redirect_uri with:
| Parameter | Description |
|---|---|
error | Error code (e.g., access_denied, invalid_request) |
error_description | Human-readable error description |
state | The state value from the request |
Discovery endpoint
GET /.well-known/oauth-authorization-serverReturns OAuth 2.0 Authorization Server Metadata per RFC 8414.
Response
{
"issuer": "https://your-school-domain.com",
"authorization_endpoint": "https://your-school-domain.com/oauth/authorize",
"token_endpoint": "https://your-school-domain.com/api/oauth/token",
"token_endpoint_auth_methods_supported": ["none", "client_secret_post"],
"revocation_endpoint": "https://your-school-domain.com/api/oauth/revoke",
"registration_endpoint": "https://your-school-domain.com/api/oauth/register",
"response_types_supported": ["code"],
"grant_types_supported": ["authorization_code", "refresh_token"],
"code_challenge_methods_supported": ["S256"],
"scopes_supported": ["openid", "profile", "email", "courses:read", "..."],
"userinfo_endpoint": "https://your-school-domain.com/api/oauth/userinfo",
"subject_types_supported": ["public"],
"claims_supported": ["sub", "name", "picture", "email", "email_verified", "org_id", "roles"],
"service_documentation": "https://docs.loopwise.com",
"mcp_client_id": "..."
}Client registration endpoint
POST /api/oauth/registerIssues credentials for pre-registered vendor platforms only: it matches client_name against a known integration (Claude Code, Cursor, etc.) and returns that platform's credentials. It is not open dynamic client registration (RFC 7591) — an unrecognized client_name is refused with invalid_client_metadata. A client that is not a pre-registered vendor uses a Client ID Metadata Document instead, where the server permits the document's host (an allowlisted host, or any host when open registration is enabled — see client_id_metadata_document_supported in the discovery metadata).
Request body
| Field | Type | Required | Description |
|---|---|---|---|
client_name | string | Yes | Name matched against a known vendor platform |
redirect_uris | string[] | No | List of allowed redirect URIs |
grant_types | string[] | No | Defaults to ["authorization_code", "refresh_token"] |
response_types | string[] | No | Defaults to ["code"] |
token_endpoint_auth_method | string | No | Defaults to "none" (public client) |
Response
{
"client_id": "abc123...",
"client_name": "Claude Code",
"redirect_uris": ["http://127.0.0.1:41234/callback"],
"grant_types": ["authorization_code", "refresh_token"],
"response_types": ["code"],
"token_endpoint_auth_method": "none",
"scope": "openid profile email courses:read ..."
}The response carries no client_secret: it declares token_endpoint_auth_method: "none", meaning the client does not authenticate at the token endpoint at all. PKCE is not a substitute for that — it protects the authorization code itself, by requiring the code_verifier matching the code_challenge sent at authorization.