External auth
Public routes that let an external service sign users in with their rCTF account.
These routes implement “Sign in with rCTF” for external services. Users approve access at /external-auth/authorize, and the external service exchanges the resulting code through the APIs documented here.
See Admin for the routes that register and revoke clients. External apps walks operators through the complete setup.
Warning (Not OAuth2)
The flow uses familiar OAuth2 field names, including client_id, redirect_uri, code, and
state, but it does not implement OAuth2. It has no scopes, refresh tokens, PKCE, OIDC
discovery, token introspection, or revocation. /token returns an ordinary rCTF login token
with full access to the user’s account.
Flow
- The external service sends the user to
/external-auth/authorize?client_id=...&redirect_uri=...&state=.... - The consent page calls
GET /api/v2/external-auth/clients/:idto render the client name and verify the redirect URI. - The user logs into rCTF if needed, then approves. The page calls
POST /api/v2/external-auth/authorizewith the user’s session token and receives aredirectToURL. - The browser navigates to
redirect_uri?code=...&state=.... - The external service’s backend exchanges the code through
POST /api/v2/external-auth/tokenand receives{accessToken, tokenType: "bearer"}. - The service uses the access token in
Authorization: Bearer ...against any rCTF endpoint - typicallyGET /api/v2/users/meto identify the team.
Failure model
An unknown client, wrong secret, mismatched redirect URI, or invalid code all return 400 badExternalAuthRequest. The response does not reveal which check failed. POST /api/v2/external-auth/authorize also returns 401 badToken when the user’s session token is missing or invalid, and 403 badPerms when the team is banned.
Code lifetime
Authorization codes expire after 60 seconds and can only be used once. Deleting a client prevents future code exchanges but does not revoke access tokens already issued to that client.