Skip to content

Authentication API Reference

Complete reference for all authentication endpoints.

Base URL: http://localhost:8000/api/v1/auth (development)

Authentication: Most endpoints require valid JWT access token via HttpOnly cookie.


Status & Info

GET /status

System health check.

Response:

{
  "status": "operational"
}

GET /me

Get current authenticated user information.

Auth Required: Yes

Response:

{
  "user_id": 123,
  "user_name": "John Doe",
  "team_id": 456,
  "team_name": "Acme Corp",
  "role_id": 1,
  "role_name": "Owner",
  "permissions": ["*"]
}


Authentication

POST /login

Step 1 of two-step login. Verify credentials and get pre-auth token.

Auth Required: No

Rate Limited: Yes (per IP)

Request:

{
  "email": "user@example.com",
  "password": "password123",  # pragma: allowlist secret
  "remember_me": false
}

Response (200 OK):

{
  "pre_auth_token": "random-token-48-chars",
  "teams": [
    {
      "team_id": 456,
      "team_name": "Acme Corp",
      "role_name": "Owner",
      "status": "ACTIVE"
    }
  ]
}

Response (422 Unprocessable):

{
  "detail": "Email verification required",
  "email": "user@example.com"
}


POST /session-exchange

Step 2 of two-step login. Exchange pre-auth token for JWT cookies.

Auth Required: No (uses pre-auth token)

Request:

{
  "pre_auth_token": "random-token-48-chars",
  "team_id": 456,
  "session_info": {
    "device_fingerprint": "sha256-hash",
    "ip": "1.2.3.4",
    "user_agent": "Mozilla/5.0...",
    "geo": {
      "city": "San Francisco",
      "country": "US"
    }
  }
}

Response (200 OK) + Sets Cookies: - mbpanel_access (HttpOnly, 6h TTL) - mbpanel_refresh (HttpOnly, 7d/1d TTL) - mbpanel_csrf (non-HttpOnly for double-submit)

{
  "user_id": 123,
  "user_name": "John Doe",
  "team_id": 456,
  "team_name": "Acme Corp",
  "role_id": 1,
  "role_name": "Owner",
  "permissions": ["*"]
}

Response (423 Locked):

{
  "detail": {
    "status": "pending",
    "token": "concurrent-login-token"
  }
}


POST /refresh

Rotate refresh token and get new access token.

Auth Required: Yes (refresh token cookie) CSRF Protected: Yes

Response (200 OK) + Sets Cookies:

{
  "access_token": "...",
  "refresh_token": "..."
}


POST /logout

Invalidate current session and clear cookies.

Auth Required: Yes CSRF Protected: Yes

Response (200 OK):

{
  "message": "Successfully logged out"
}


Device Approval

POST /device/challenge

Request OTP for new device approval.

Auth Required: No (uses pre-auth token)

Request:

{
  "pre_auth_token": "random-token-48-chars",
  "device_fingerprint": "sha256-hash",
  "ip": "1.2.3.4",
  "user_agent": "Mozilla/5.0..."
}

Response (200 OK):

{
  "message": "OTP sent to email"
}


POST /device/approve

Verify OTP and approve device.

Auth Required: No (uses pre-auth token)

Request:

{
  "pre_auth_token": "random-token-48-chars",
  "device_fingerprint": "sha256-hash",
  "otp_code": "123456"
}

Response (200 OK):

{
  "message": "Device approved"
}


Suspicious Login

POST /login/approve

Approve suspicious login from email link.

Auth Required: No (uses alert token)

Request:

{
  "token": "alert-token-from-email"
}

Response (200 OK):

{
  "status": "approved"
}


POST /login/deny

Deny suspicious login from email link.

Auth Required: No (uses alert token)

Request:

{
  "token": "alert-token-from-email"
}

Response (200 OK):

{
  "status": "denied"
}


Registration

POST /register-owner

Door A registration: Create user + team (requires billing upgrade).

Auth Required: No

Rate Limited: Yes

Request:

{
  "email": "user@example.com",
  "password": "password123",  # pragma: allowlist secret
  "name": "John Doe",
  "team_name": "Acme Corp",
  "team_slug": "acme-corp"
}

Response (201 Created):

{
  "user_id": 123,
  "team_id": 456,
  "message": "Registration successful. Please verify your email."
}


POST /register-from-invite

Door B registration: Join existing team via invite token.

Auth Required: No

Rate Limited: Yes

Request:

{
  "invite_token": "invite-token-from-email",
  "email": "user@example.com",
  "password": "password123",  # pragma: allowlist secret
  "name": "John Doe"
}

Response (201 Created):

{
  "user_id": 123,
  "team_id": 456,
  "role_id": 3,
  "role_name": "Developer",
  "message": "Registration successful. Please verify your email."
}


Email Verification

POST /email/verification/request

Request email verification token.

Auth Required: No

Request:

{
  "email": "user@example.com"
}

Response (200 OK):

{
  "message": "Verification email sent"
}


POST /email/verification/confirm

Confirm email verification with token.

Auth Required: No

Request:

{
  "token": "verification-token-from-email"
}

Response (200 OK):

{
  "message": "Email verified successfully"
}


Password Reset

POST /password-reset/request

Request password reset token.

Auth Required: No

Request:

{
  "email": "user@example.com"
}

Response (200 OK):

{
  "message": "Password reset email sent"
}


POST /password-reset/confirm

Reset password with token.

Auth Required: No

Request:

{
  "token": "reset-token-from-email",
  "new_password": "new-password123"  # pragma: allowlist secret
}

Response (200 OK):

{
  "message": "Password reset successfully"
}


TOTP (2FA)

POST /totp/setup

Initialize TOTP setup (generates secret + QR code).

Auth Required: Yes CSRF Protected: Yes

Response (200 OK):

{
  "secret": "JBSWY3DPEHPK3PXP",  # pragma: allowlist secret
  "qr_code_url": "otpauth://totp/...",
  "backup_codes": ["12345678", "87654321", ...]
}


POST /totp/verify

Verify TOTP code and enable 2FA.

Auth Required: Yes CSRF Protected: Yes

Request:

{
  "totp_code": "123456"
}

Response (200 OK):

{
  "message": "TOTP enabled successfully"
}


POST /totp/backup

Use backup code to verify TOTP.

Auth Required: Yes CSRF Protected: Yes

Request:

{
  "backup_code": "12345678"
}

Response (200 OK):

{
  "message": "Backup code verified"
}


Activity & Devices

GET /login-activity

Get recent login/refresh activity.

Auth Required: Yes

Response (200 OK):

{
  "activity": [
    {
      "id": 1,
      "event_type": "login",
      "ip": "1.2.3.4",
      "user_agent": "Mozilla/5.0...",
      "device_fingerprint": "...",
      "geo": {"city": "SF", "country": "US"},
      "created_at": "2025-01-22T10:30:00Z"
    }
  ]
}


GET /trusted-devices

List trusted devices for current user.

Auth Required: Yes

Response (200 OK):

{
  "devices": [
    {
      "id": 1,
      "device_label": "Chrome on macOS",
      "user_agent": "...",
      "first_ip": "1.2.3.4",
      "last_ip": "1.2.3.4",
      "first_seen_at": "2025-01-01T00:00:00Z",
      "last_seen_at": "2025-01-22T10:30:00Z",
      "trusted_at": "2025-01-01T00:00:00Z",
      "revoked_at": null
    }
  ]
}


POST /trusted-devices/revoke

Revoke a trusted device.

Auth Required: Yes CSRF Protected: Yes

Request:

{
  "device_id": 1
}

Response (200 OK):

{
  "message": "Device revoked"
}


Error Responses

Status Code Description
401 not_authenticated Missing or invalid token
403 missing_permission User lacks required permission
403 csrf_mismatch CSRF token validation failed
422 validation_error Request validation failed
423 concurrent_login_pending Another session active - approval pending
423 concurrent_login_denied Concurrent login was denied
429 rate_limit_exceeded Too many attempts
500 internal_error Server error

See Error Codes for complete reference.