There are no public API keys, no OAuth for third parties, and no user-issued tokens.
Browser session
Signing in with Discord
Sign-in is a browser redirect flow, not a JSON exchange.1
Start
The browser navigates to
GET /api/auth/discord. Argus creates a single-use state, valid for ten minutes, binds it to this browser with a short-lived cookie, and redirects to Discord asking for the identify scope.2
Callback
Discord redirects to
GET /api/auth/discord/callback. Argus checks the state against the cookie, exchanges the code, and creates or updates the Argus account from the Discord profile.3
Session
Argus sets the session cookie and redirects to the application root. Any previous session in that browser is replaced.
The session cookie
The cookie is
HttpOnly, so scripts cannot read it. Same-origin fetch sends it automatically.
On every request Argus re-checks the session’s expiry, the account’s status and the current staff membership. A suspended or disabled account is refused with ACCOUNT_DISABLED, and suspending an account revokes its sessions.
Origin check on changes
Every cookie-authenticated request other thanGET must carry an Origin header equal to the application’s own origin (APP_URL). Anything else is refused with 403 INVALID_ORIGIN. Browsers add this header themselves on same-origin requests.
Argus sends no CORS headers. A page on another origin cannot call this API with a user’s session.
Signing out
POST /api/auth/logout revokes the current session and clears the cookie.
Linking a Roblox account
A signed-in user can prove ownership of a Roblox account throughGET /api/auth/roblox, an authorisation-code flow with PKCE. The callback must arrive in a session belonging to the user who started it. A Roblox account can be linked to one Argus account, and there is no unlinking endpoint.
Service credentials
An administrator can issue a credential for an integration withPOST /api/admin/services. The response contains the token once; Argus keeps only its hash.
- Scopes are permission keys. A credential can do exactly what its scopes allow.
admin.manageandstaff.managecannot be granted. - It expires. The lifetime is 1 to 90 days, 30 by default. Revocation takes effect on the next request.
- It is not a user. Endpoints that need a signed-in person refuse it with
403 USER_REQUIRED. Those are: the current user, sign-out, Developer Access, Roblox linking, all administration including staff membership, everything in the civilian portal, every official PNC change, and all MDT self-service. - It is never mixed with a cookie. If an
Authorizationheader is present and invalid, the request fails with401; Argus does not fall back to the session. - No origin check. Bearer requests do not need an
Originheader.
serviceId. A credential cannot claim to be a person.
Each operation in the reference states its access: Browser session only, or Browser session, or a service credential.
Developer Access
POST /api/auth/developer with the developer password gives the current session every permission in the catalogue. DELETE /api/auth/developer turns it off.
- It is off unless the server has
ARGUS_DEVELOPER_PASSWORDset. Clearing that variable disables it for sessions that already had it. - It changes no account, role or staff record, and does not affect the user’s other sessions.
- It does not create a staff profile. Rules that need a real one still apply: for example booking on to a unit, starting a shift, or hosting a session.
- Attempts are limited to five per account per 15 minutes. A wrong password, a malformed body and a disabled feature all return the same
401 AUTHENTICATION_FAILED. GET /api/mereports it asdeveloperAccess: true, with the expandedpermissions.
Rate limits
Limits are counted per caller, per minute, in the database, so they hold across server instances.
Exceeding one returns
429 RATE_LIMITED with a Retry-After header in seconds.