Authentication & account API
HTTP reference for sign-in and the JWT session flow, account and profile management, sessions, two-factor authentication and programmatic API-token management.
All paths are relative to https://api.aleex-rank.ai/api/v2 and return the standard {"success": true, "data": {...}} envelope (see REST API). Authentication uses two headers that are not interchangeable: Authorization: Bearer <jwt> carries the web session, and X-API-Key: rk_... carries a programmatic API token. For the concepts behind both credentials — JWT vs API tokens, scoping and tier limits — read Authentication & API tokens.
Credential model
The endpoints on this page fall into three buckets:
- Public (no credential):
login,register,refresh,forgot-password,reset-password,verify-email, and the two-factor login steps (2fa/verify,2fa/verify-backup). These are the JWT/web flow — they exist to obtain a session, so you cannot call them with anX-API-Key. A successfullogin(or 2FA completion) returns a JWT access token and refresh token. - Authenticated with either credential: every other endpoint accepts a valid JWT or an API token. Account, profile, session and 2FA management all work the same whether you authenticate the browser session or a
rk_token. - Tier-gated: the API-token endpoints additionally require a plan that includes API tokens. The lowest tier (Casual) cannot manage personal tokens and receives
403.
Missing or invalid credentials return 401 with Use "Authorization: Bearer <jwt>" or "X-API-Key: <api_token>".
Session & account lifecycle
Sign in
POST /auth/login
login is public. Send the account credentials:
{"email": "alice@example.com", "password": "s3cret-passphrase"}
When 2FA is not enabled, the response carries the account record and a fresh token pair (expires_in is the access-token lifetime in seconds):
{
"success": true,
"data": {
"user": {"user_id": 428193, "username": "alice", "email": "alice@example.com", "tier_id": 2},
"tokens": {
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"token_type": "Bearer",
"expires_in": 3600
}
}
}
When the account has 2FA enabled, login instead returns a short-lived temp_token and no session yet — finish the login at /auth/2fa/verify:
{
"success": true,
"data": {"requires_2fa": true, "temp_token": "eyJhbGci...", "expires_in": 300}
}
Repeated failures are throttled per email and return 429; a suspended account returns 403.
Register
POST /auth/register
Public. username, email, password, country (ISO 3166-1 alpha-2), region and language (ISO 639-1) are required; password_confirmation and referral_code are optional:
{
"username": "alice",
"email": "alice@example.com",
"password": "s3cret-passphrase",
"country": "US",
"region": "California",
"language": "en"
}
New accounts start on the Casual tier with an unverified email. The 201 response mirrors login and adds email_verification_sent:
{
"success": true,
"data": {
"user": {"user_id": 428193, "username": "alice", "email": "alice@example.com", "tier_id": 1},
"tokens": {"access_token": "...", "refresh_token": "...", "token_type": "Bearer", "expires_in": 3600},
"email_verification_sent": true
}
}
Refresh the session
POST /auth/refresh
Public. Exchange a valid refresh token for a new pair; the old refresh token is rotated out (revoked) on use.
{"refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."}
{
"success": true,
"data": {"access_token": "...", "refresh_token": "...", "token_type": "Bearer", "expires_in": 3600}
}
Refresh tokens are single-use. If an already-rotated token is replayed, the platform treats it as theft, revokes every session for that user and returns 401.
Password reset
POST /auth/forgot-password
POST /auth/reset-password
Both are public. forgot-password emails a reset link (rate-limited to one request every two minutes per email):
{"email": "alice@example.com"}
{"success": true, "data": {"message": "Email sent"}}
reset-password consumes the 64-character token from that email and sets a new password (minimum 8 characters). All existing sessions are revoked for safety:
{"token": "9f2c...<64 hex chars>...a1", "password": "new-s3cret-passphrase"}
{
"success": true,
"data": {"message": "Password has been reset successfully. Please login with your new password."}
}
Email verification
GET /auth/verify-email
POST /auth/resend-verification
GET /auth/verify-email?token=<64 hex chars> is public and confirms the address from the link:
{
"success": true,
"data": {"message": "Email verified successfully. You now have full access to all features.", "verified": true}
}
POST /auth/resend-verification requires a credential and re-sends the link to the current account (rate-limited, 429 if requested too soon; 400 if already verified):
{"success": true, "data": {"message": "Verification email sent"}}
Current account
GET /auth/me
Returns the full account profile for the authenticated credential — identity, effective tier (with its limits and permissions), trial and subscription status, teams with your roles, and assigned models and agents:
{
"success": true,
"data": {
"user_id": 428193,
"username": "alice",
"email": "alice@example.com",
"country": "US",
"region": "California",
"language": "en",
"verified": true,
"is_banned": false,
"tier": {"id": 2, "name": "Pro", "max_pentests_per_month": 20, "max_api_tokens": 3, "max_agents": 10},
"trial": {"active": false},
"subscription": {"status": "active", "billing_interval": "month"},
"teams": [{"id": 4, "name": "Security Team", "is_owner": true, "roles": []}],
"assigned_models": ["gpt-5"],
"assigned_agents": ["Recon Agent"],
"assigned_agents_count": 1
}
}
Update the account
PUT /auth/profile
PUT /auth/email
PUT /auth/password
PUT /auth/username
Each requires a credential (PATCH is also accepted). PUT /auth/profile only updates country, region and language and returns the updated record:
{"country": "ES", "region": "Madrid", "language": "es"}
PUT /auth/email changes the address, clears the verified flag and sends a fresh verification email:
{"email": "alice.new@example.com"}
{
"success": true,
"data": {
"message": "Email updated successfully. Please verify your new email address.",
"user": {"user_id": 428193, "email": "alice.new@example.com"},
"email_verification_sent": true
}
}
PUT /auth/password verifies the current password before setting the new one (minimum 8 characters):
{"current_password": "s3cret-passphrase", "new_password": "even-better-passphrase"}
{"success": true, "data": {"message": "Password updated successfully"}}
PUT /auth/username updates the display name (2–100 characters) and returns the updated record:
{"username": "alice-prime"}
Sessions
These endpoints operate on the JWT sessions behind the web app. You can call them with either credential, but they list and revoke browser sessions, not API tokens (use the API-token endpoints below to manage those).
GET /auth/sessions
GET /auth/sessions-active
DELETE /auth/session
DELETE /auth/logout
GET /auth/sessions is the paginated login history; GET /auth/sessions-active lists only sessions that are still valid. Both return the items + pagination shape (accepts page and per_page):
{
"success": true,
"data": {
"items": [
{
"id": 8821,
"creation_date": "2026-01-12 17:47:16",
"expiration_date": "2026-01-12 18:47:16",
"userdata": {"ip": "203.0.113.7", "user_agent": "Mozilla/5.0", "accept_language": "en-US"},
"status": "active"
}
],
"pagination": {"total": 1, "count": 1, "per_page": 20, "current_page": 1, "total_pages": 1}
}
}
DELETE /auth/session revokes one session by its id:
{"session_id": 8821}
DELETE /auth/logout revokes all of the user’s sessions at once:
{"success": true, "data": {"message": "Logged out successfully"}}
Delete the account
DELETE /auth/account
Soft-deletes the account and revokes every session. The current password is required as confirmation:
{"password": "s3cret-passphrase"}
{"success": true, "data": {"message": "Account deleted successfully"}}
Two-factor authentication (TOTP)
Rank supports time-based one-time passwords (RFC 6238) compatible with Google Authenticator, Authy and similar apps, plus single-use backup codes. The management endpoints require a credential; the two verify endpoints are public because they finish a login.
Status, setup and enable
GET /auth/2fa/status
POST /auth/2fa/setup
POST /auth/2fa/enable
GET /auth/2fa/status reports whether 2FA is available in this environment and whether the account has it on:
{
"success": true,
"data": {
"available": true,
"enabled": false,
"verified_at": null,
"backup_codes_remaining": 0,
"last_used_at": null
}
}
POST /auth/2fa/setup (no body) generates a secret and returns the otpauth:// URL to render as a QR code, plus a manual_entry_key for typing the secret by hand. The secret is stored but 2FA is not active yet:
{
"success": true,
"data": {
"message": "Scan the QR code with your authenticator app, then verify with a code to enable 2FA.",
"secret": "JBSWY3DPEHPK3PXP...",
"qr_code_url": "otpauth://totp/Rank:alice@example.com?secret=JBSWY3DPEHPK3PXP&issuer=Rank",
"manual_entry_key": "JBSW Y3DP EHPK 3PXP"
}
}
POST /auth/2fa/enable activates 2FA after the first 6-digit code checks out, and returns the backup codes once:
{"code": "123456"}
{
"success": true,
"data": {
"message": "2FA has been enabled successfully. Save your backup codes in a safe place!",
"enabled": true,
"backup_codes": ["A2B4C6D8", "E3F5G7H9", "..."],
"backup_codes_warning": "These codes will NOT be shown again. Store them securely."
}
}
Regenerate backup codes
POST /auth/2fa/backup-codes
Requires a valid TOTP code and replaces the existing backup codes (the previous set is invalidated). The new codes are shown only in this response:
{"code": "123456"}
{
"success": true,
"data": {
"message": "Backup codes have been regenerated. Save them in a safe place!",
"backup_codes": ["K2L4M6N8", "P3Q5R7S9", "..."],
"backup_codes_warning": "These codes will NOT be shown again. Store them securely. Previous codes are now invalid."
}
}
Disable
DELETE /auth/2fa/disable
Turns 2FA off after verifying a current code:
{"code": "123456"}
{"success": true, "data": {"message": "2FA has been disabled successfully.", "enabled": false}}
Completing a 2FA login
POST /auth/2fa/verify
POST /auth/2fa/verify-backup
Both are public and consume the temp_token returned by login. 2fa/verify takes a 6-digit authenticator code:
{"temp_token": "eyJhbGci...", "code": "123456"}
A success returns the same {user, tokens} payload as a normal login. 2fa/verify-backup takes a one-time backup_code instead and additionally reports how many codes remain:
{"temp_token": "eyJhbGci...", "backup_code": "A2B4C6D8"}
{
"success": true,
"data": {
"user": {"user_id": 428193, "username": "alice", "email": "alice@example.com"},
"tokens": {"access_token": "...", "refresh_token": "...", "token_type": "Bearer", "expires_in": 3600},
"backup_codes_remaining": 4
}
}
API tokens
These endpoints are the programmatic equivalent of the dashboard Settings > API Tokens flow described in Authentication & API tokens — read that page for the concepts, scoping rules and per-tier token limits. They require a credential and a tier that includes API tokens; Casual accounts cannot manage personal tokens and receive 403.
Available permissions
GET /auth/api-tokens/available-permissions
Lists the permissions you may assign to a token (grouped by tag), the available tags, and the teams you can scope a token to. Use it to discover valid permission_ids, tags and team_ids before creating a token:
{
"success": true,
"data": {
"permissions": {
"pentest": [{"id": 12, "name": "pentests.create", "method": "POST", "description": "Launch a pentest"}]
},
"tags": ["agent", "pentest", "vulnerability"],
"teams": [{"id": 4, "name": "Security Team"}]
}
}
List tokens
GET /auth/api-tokens
Paginated (page, per_page, and include_revoked=true to include revoked tokens). Each item exposes metadata only — never the secret — and scoped tokens include their resolved permissions and teams. The limits block reports the relevant token pool:
{
"success": true,
"data": {
"items": [
{
"id": 12,
"user_id": 428193,
"name": "CI/CD pipeline",
"scoped": true,
"created_at": "2026-01-12 17:47:16",
"last_used_at": "2026-01-13 09:02:55",
"revoked": 0,
"permissions": [{"id": 12, "name": "pentests.create", "method": "POST", "tag": "pentest"}],
"teams": [{"id": 4, "team_name": "Security Team"}]
}
],
"pagination": {"total": 1, "count": 1, "per_page": 20, "current_page": 1, "total_pages": 1},
"limits": {"max_tokens": 3, "active_tokens": 1, "remaining": 2, "is_unlimited": false, "context": "tier", "context_name": "Pro"}
}
}
Create a token
POST /auth/api-tokens
All fields are optional — omitting every scope field creates a full-access token that mirrors your own permissions. Scope a token by permission_ids and/or tags (combined), and restrict it to specific workspaces with team_ids. A token tied to a team counts against that team’s shared pool instead of your individual pool (see Teams API and Teams & tiers):
{
"name": "CI/CD pipeline",
"tags": ["pentest"],
"permission_ids": [12, 13],
"team_ids": [4]
}
The 201 response is the only time the plaintext rk_ token is returned — store it immediately, as it cannot be retrieved again:
{
"success": true,
"data": {
"message": "API token created successfully. Save this token - it will not be shown again!",
"token": "rk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"token_info": {
"id": 12,
"name": "CI/CD pipeline",
"scoped": true,
"created_at": "2026-01-12 17:47:16",
"last_used_at": null,
"prefix": "rk_xxxx...",
"permissions": [{"id": 12, "name": "pentests.create", "method": "POST", "tag": "pentest"}],
"teams": [{"id": 4, "team_name": "Security Team"}]
},
"limits": {"max_tokens": 3, "active_tokens": 2, "remaining": 1, "is_unlimited": false, "context": "tier", "context_name": "Pro"}
}
}
A token can never carry more permissions than its creator, and scoping is validated at creation time: unknown tags, restricted permissions, or teams you do not belong to are rejected with 400. Reaching the token limit for the target pool also returns 400.
Rename a token
PUT /auth/api-tokens
Renames a token by token_id (PATCH is also accepted; names are capped at 100 characters). This is metadata only and does not rotate the secret:
{"token_id": 12, "name": "CI/CD pipeline (staging)"}
{"success": true, "data": {"message": "API token updated successfully"}}
Revoke tokens
DELETE /auth/api-tokens
DELETE /auth/api-tokens/all
DELETE /auth/api-tokens revokes a single token by token_id:
{"token_id": 12}
{"success": true, "data": {"message": "API token revoked successfully"}}
DELETE /auth/api-tokens/all revokes every token you own at once and reports how many were affected:
{
"success": true,
"data": {"message": "All API tokens revoked successfully", "tokens_revoked": 3}
}