Guide
Authentication
The SwiftGoma API uses short-lived access tokens paired with longer-lived refresh tokens. Accounts can sign in with a password, a one-time email code, a passkey, or Google — and can optionally add TOTP-based two-factor authentication on top of any of them. Every endpoint mentioned on this page lives under https://api.swiftgoma.com/api/v1/auth.
Access and refresh tokens
A successful sign-in produces two tokens. The access token is short-lived and sent with every authenticated request. The refresh token lives much longer and is only used to obtain a new access token via POST /refresh-token once the access token expires. Neither token is ever returned in a way your client needs to parse manually on web — see below.
Web vs. mobile sessions
Browser and mobile clients receive their tokens differently, and every login and session endpoint behaves accordingly based on one header:
// Web (browser)
// Access & refresh tokens are set as httpOnly cookies automatically.
// Just send credentials on every request:
fetch(url, { credentials: "include" });
// Mobile
// Send this header on every request, and manage the tokens yourself:
fetch(url, { headers: { "x-client-type": "mobile" } });Why the difference?
Ways to sign in
All four methods converge on the same result — a session for web, or a token pair for mobile — and all four can be intercepted by a two-factor challenge if the account has TOTP enabled.
| Method | Starts with | Finishes with |
|---|---|---|
| Password | no request needed | POST /login/password |
| Passwordless email code | POST /login/request-otp | POST /login/verify-otp |
| Passkey (WebAuthn) | POST /passkey/login/options | POST /passkey/login/verify |
Google ID token from client SDK | POST /login/google |
Password login
- 1
Send email and password
POST /login/passwordwithemailandpassword. - 2
Handle the result
If the account doesn't have 2FA enabled, you get a session immediately. If it does, you get a pendingToken instead — see Two-factor authentication below.
Passwordless email code
- 1
Request a code
POST /login/request-otpwith just theemail. The response is identical whether or not the address is registered, so this step never reveals account existence. - 2
Verify the code
The user receives a code by email. Submit it toPOST /login/verify-otpalong with theemail.
Passkey
- 1
Get a challenge
POST /passkey/login/optionswith theemailreturns a WebAuthn assertion challenge and achallengeId. - 2
Resolve it with the browser
Pass the challenge tonavigator.credentials.get()in the browser. - 3
Verify the assertion
Send the browser's response and thechallengeIdtoPOST /passkey/login/verify.
Two-factor authentication
When an account has TOTP enabled, every login method above returns this instead of a session:
{
"success": true,
"data": {
"requiresTotp": true,
"pendingToken": "mfa_9f8e7d6c5b4a3210"
}
}Prompt the user for their 6-digit authenticator code (or an unused backup code), then finish with POST /login/totp, passing the pendingToken.
Turning it on
- 1
Start setup
POST /totp/setup (authenticated) returns a secret and a QR code to scan into an authenticator app. - 2
Confirm it
POST /totp/confirm with the first 6-digit code turns 2FA on and returns a one-time set of backup codes — show these to the user immediately, they aren't retrievable later.
Backup codes
Password management
| Situation | Endpoint |
|---|---|
| Forgot password | POST /password/forgot then POST /password/reset |
| Change known password | POST /password/update |
| Set a first password (Google/passkey-only accounts) | POST /password/create |
Session management
A signed-in user can inspect and manage their own active sessions:
| Action | Endpoint |
|---|---|
| List active sessions | GET /sessions |
| Sign out one device | DELETE /sessions/:sessionId |
| Sign out everywhere | POST /logout-all |
Rate limits
Auth endpoints are grouped into tiers with different limits, tightest where the risk of abuse is highest:
| Tier | Applies to | Behavior |
|---|---|---|
| Credential check | login/password, login/verify-otp, password/reset, totp confirm/disable | Tightest limits, scoped by IP and by account. Repeated failures feed automatic IP blocking. |
| Request / initiation | login/request-otp, password/forgot, resend-verification | Limited per IP and per account, with a resend cooldown, to prevent inbox or SMS flooding. |
| Account creation | create-account, register/google, login/google | Tightly limited per IP, and screened for automated traffic before hitting the limiter. |
| Session | me, logout, sessions, refresh-token | Looser limits — these don't touch credentials. |
| Authenticated action | totp/setup, passkey registration, password/create | Requires a valid session already; moderate limits. |
Error handling
Errors share one shape:
{
"success": false,
"error": {
"code": "UNAUTHORIZED",
"message": "Identifiants invalides."
}
}Enumeration-safe by design
POST /login/request-otp and POST /password/forgot always return the same generic success message, whether or not the email is registered — the API deliberately doesn't reveal which emails have accounts.