Skip to content
AquadactylAquadactyl
API reference

Browser authentication

Password login, two-factor checkpoints, passkey ceremonies, OAuth linking and session-only account security endpoints.

These endpoints serve the panel's browser application. They use the web session, cookies, and CSRF protection. Passkeys and account linking do not accept a bearer API key in place of a browser session. External automation should use a Client or Application API key.

The tables below describe the pinned panel's auth routes and account security routes. Sign-in methods must be enabled and configured by an administrator.

Password and session endpoints

Method and pathInputResult
POST /auth/loginuser (username or email), password, plus the configured captcha response when requireddata.complete: true and session, or data.complete: false and a 2FA confirmation_token.
POST /auth/login/checkpointconfirmation_token plus authentication_code or recovery_tokenCompletes the pending login and establishes the session.
POST /auth/registerusername, email, password, password_confirmation, plus captcha when requiredCreates an account only when registration is enabled; returns the login response.
POST /auth/passwordemail, plus configured captcha responseA JSON status message. The response deliberately does not reveal whether an account exists.
POST /auth/password/resetReset token, email, password, password_confirmation; new password at least 8 characterssuccess, redirect_to, and send_to_login; 2FA accounts must log in again.
POST /auth/logoutNo application-specific input; authenticated session and CSRFClears the session using Laravel's authentication flow.
GET /auth/methodsOptional oauth=checkpoint after an OAuth redirectpasskeys_enabled, public providers, pending confirmation_token, and any one-time error.

The GET routes /auth/login, /auth/register, /auth/password and /auth/password/reset/{token} render the React authentication application. They are not JSON credential endpoints. Most /auth routes are guest-only; OAuth callback removes the guest restriction, and logout requires authentication. Login and checkpoint have additional failed-login lockout handling.

The 2FA challenge is stored in the same browser session and expires after 5 minutes. An incomplete login response looks like:

{
  "data": { "complete": false, "confirmation_token": "SESSION_BOUND_CHALLENGE" }
}

Do not treat this as an API token. Submit it through the same session to POST /auth/login/checkpoint. A complete response contains data.complete: true, data.intended, and data.user. OAuth and passkey login also pass through this existing checkpoint when the user has 2FA enabled.

Sources: login response and checkpoint, checkpoint validation, registration.

Passkey sign-in

  1. POST /auth/passkeys/options to obtain WebAuthn request options.
  2. Decode binary option fields, then invoke navigator.credentials.get in the browser with those options.
  3. Base64url-encode the credential's binary response fields and send them to POST /auth/passkeys/login.
  4. Complete a 2FA checkpoint when data.complete is false.

Passkey login validates the following JSON fields:

FieldConstraint
idRequired base64url credential ID, string up to 2048 characters.
response.clientDataJSONRequired base64url string, up to 8192 characters.
response.authenticatorDataRequired base64url string, up to 8192 characters.
response.signatureRequired base64url string, up to 2048 characters.
response.userHandleRequired base64url string, up to 256 characters.

WebAuthn requires a secure origin (HTTPS, or localhost) and a configured relying party origin. Options and completion must share the same session. The service checks challenge, ceremony type, origin, credential ownership, user verification and authenticator data. Do not create credential payloads by hand or reuse challenge responses. Use the panel's existing browser conversion helpers as a reference when adding a custom UI.

Source: PasskeyService rules and ceremonies.

Account security endpoints

All /account/security routes require auth:web, the normal account security requirements, and the authentication rate limiter. They use Cache-Control: no-store, private for security listings and WebAuthn options.

Method and pathInputSuccess
GET /account/securityNo body200 with passkeys_enabled, providers, passkeys, identities, notice, error.
POST /account/security/passkeys/optionscurrent_password200 WebAuthn registration options.
POST /account/security/passkeysRegistration credential fields below204 after registering the credential.
DELETE /account/security/passkeys/{id}current_password; numeric passkey ID204; only the current user's credential can be removed.
POST /account/security/oauth/{provider}current_password200 with redirect, the URL to navigate to for account linking.
DELETE /account/security/oauth/{id}current_password; numeric identity ID204; unlinks the current user's identity.

Password confirmation accepts a required current_password string up to 1024 characters and verifies it against the authenticated account. A bearer key is explicitly insufficient for this confirmation.

To register a passkey, request registration options, call navigator.credentials.create, then send:

FieldConstraint
idRequired base64url credential ID, up to 2048 characters.
nameRequired user-facing credential name, up to 100 characters.
response.clientDataJSONRequired base64url string, up to 8192 characters.
response.attestationObjectRequired base64url string, up to 131072 characters.
response.transportsOptional array, at most 8 entries: usb, nfc, ble, internal, hybrid, smart-card.

The security listing returns passkeys with id, name, created_at, and last_used_at; identities have id, provider, display_name, created_at, and last_used_at. Private credentials and provider secrets are not returned. The notice and error values are consumed from the session on read.

Sources: account security controller, password confirmation.

OAuth sign-in and linking

Providers are discord, github, google, and oidc, subject to administrator configuration. GET /auth/oauth/{provider} redirects to the provider; GET /auth/oauth/{provider}/callback is its configured return URL. Preserve the browser's session and the provider's state parameters throughout the flow.

Sign-in uses an already-linked provider identity. The callback does not silently create or merge accounts based on an email match. Existing users first sign in with their password and link a provider through Account settings. For linking, POST to /account/security/oauth/{provider}, navigate to the returned redirect, then let the provider callback finish the operation. Success returns to /account; errors are surfaced through the session notice/error fields.

If OAuth sign-in requires 2FA, the callback redirects to /auth/login?oauth=checkpoint. The frontend reads GET /auth/methods?oauth=checkpoint and completes the existing login checkpoint.

Source: OAuth controller.

Locale responses

GET /locales/locale.json serves the frontend translation loader. It accepts locale and namespace values used by the panel's i18next configuration and returns translation objects. Follow the locale controller when writing a translation loader; account language selection uses the Client API's /account/language endpoint.