Authentication
Admin login with Discord, the signed-in admin's profile, logout, and the session cleanup job.
Project-scoped login (/auth/authorize), backend-to-backend session API (/auth/token, /auth/validate, /auth/logout, /auth/token/refresh), and system-admin Discord OAuth (/auth/admin/*). Use /auth/authorize when you need to force a fresh Discord consent (step-up auth) or to stay on the pre-SSO flow.
Initiate system admin Discord OAuth2 login
/api/auth/admin/discordReturns a Discord authorization URL. The admin opens the URL, authenticates with Discord, and is redirected to the admin callback endpoint.
A CLI (mcid-cli) can instead receive the result itself: pass a loopback redirect_uri plus a PKCE S256 code_challenge (RFC 8252 / RFC 7636). After Discord, MCID redirects to that URL with ?code=&state= (or ?error=&state=), and the CLI exchanges the code at POST /auth/admin/token.
Authentication: None, this endpoint is public.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
redirect_uri | query | string | no | CLI login only: the loopback URL (http, 127.0.0.1 / localhost / [::1], explicit port) MCID redirects to with ?code=&state= (or ?error=&state=) once Discord is done. |
code_challenge | query | string | no | CLI login only: PKCE challenge, BASE64URL(SHA256(code_verifier)) (RFC 7636). |
code_challenge_method | query | string | no | CLI login only: must be S256. |
Responses
| Status | Description | Body |
|---|---|---|
200 | Discord authorization URL. | any |
400 | Invalid CLI login parameters (non-loopback redirect_uri, missing or malformed PKCE challenge). |
Open in Swagger (opens in a new tab)
Log out of the admin dashboard
/api/auth/admin/logoutInvalidates the current admin session and clears the admin_session httpOnly cookie. Accepts the token via Authorization: Bearer or the admin_session cookie, same as other admin routes.
Authentication: Admin session token (Authorization: Bearer <token>)
Responses
| Status | Description | Body |
|---|---|---|
200 | Logout successful. | SuccessResponseDto |
401 | Missing, invalid, or expired session token. |
Open in Swagger (opens in a new tab)
Get current system admin profile
/api/auth/admin/meReturns the profile of the authenticated system admin based on their Bearer session token or the admin_session httpOnly cookie set after Discord OAuth2 login. Also returns root and the effective access level per admin resource (permissions), which the admin panel uses to decide what to show. Any valid admin session succeeds, including one whose member holds no access yet. Useful for verifying a token is still valid and retrieving up-to-date profile data.
Authentication: Admin session token (Authorization: Bearer <token>)
Responses
| Status | Description | Body |
|---|---|---|
200 | Authenticated admin profile. | AdminMeResponseDto |
401 | Missing, invalid, or expired session token. |
Open in Swagger (opens in a new tab)
Exchange a CLI login code for an admin session
/api/auth/admin/tokenSecond half of the CLI admin login (mcid-cli). Exchanges the one-time code MCID redirected to the CLI with, plus the PKCE codeVerifier whose S256 challenge started the login, for a 24-hour admin session token. A code works once and expires quickly; every failure returns the same 401.
Authentication: None, this endpoint is public.
Request body (JSON, required): AdminCliTokenDto schema.
Responses
| Status | Description | Body |
|---|---|---|
200 | Admin session issued. | AdminCliTokenResponseDto |
401 | Unknown, used or expired code, or a code_verifier that does not match. |
Open in Swagger (opens in a new tab)
Cleanup expired sessions (maintenance)
/api/auth/cleanupRemoves expired sessions. Should be called by a scheduled job.
Authentication: None, this endpoint is public.
Responses
| Status | Description | Body |
|---|---|---|
200 | Cleanup completed. | SuccessResponseDto |
Open in Swagger (opens in a new tab)
Schemas
AdminCliTokenDto schema
| Field | Type | Required | Description |
|---|---|---|---|
code | string | yes | The one-time code from the CLI login redirect |
codeVerifier | string | yes | The PKCE code_verifier whose S256 challenge started the login (RFC 7636) |
AdminCliTokenResponseDto schema
| Field | Type | Required | Description |
|---|---|---|---|
expiresAt | string (date-time) | yes | When the session expires |
token | string | yes | Admin session token (Bearer), valid 24 hours |
AdminMeResponseDto schema
| Field | Type | Required | Description |
|---|---|---|---|
avatar | string or null | no | Discord avatar hash or full CDN URL |
displayName | string or null | no | Discord guild nickname (rewritten on every sync) |
email | string or null | no | Email address from Discord (requires email OAuth scope) |
globalName | string or null | no | Discord global display name |
id | string | yes | Member ID (Discord snowflake) |
isSystemAdmin | boolean | yes | Whether the member has the system admin flag set |
permissions | map of "none" or "read" or "write" or "manage" | yes | The effective access level per admin resource. The admin panel builds its navigation from this; the API enforces it on every request. |
preferredName | string or null | no | Admin-set display-name override (via PATCH /api/admin/profile); takes precedence over displayName in the UI when present |
root | boolean | yes | True when the member holds a root role. Root has manage on every resource. |
sessionExpiresAt | string (date-time) | yes | ISO 8601 timestamp when the current session expires |
username | string | yes | Discord username |
SuccessResponseDto schema
| Field | Type | Required | Description |
|---|---|---|---|
success | boolean | yes | Operation success status |
Source: apps/api/openapi.json.