Authentication API Reference

User registration, login, password reset, TOTP two-factor authentication, email verification, and session management.

19 endpoints

POST /api/auth/forgot-password

Request a password reset link

Always returns 200 regardless of whether the email exists, to prevent enumeration. Rate limited to 5 requests per hour per IP.

Authentication

None

Request Body

NameTypeRequiredDescription
email string (email) required

Response (Success)

NameTypeRequiredDescription
message string required

Example Request

curl -X POST "https://api.buddo.xyz/api/auth/forgot-password" \
  -H "Content-Type: application/json" \
  -d '{
  "email": "user@example.com"
}'

Example Response

{
  "message": "string"
}
POST /api/auth/login

Authenticate and receive a JWT token

Returns a JWT token on success. If the account has TOTP enabled and no totp_code is provided, returns 401 with totp_required: true. Rate limited to 10 requests per minute per IP.

Authentication

None

Request Body

NameTypeRequiredDescription
email string (email) required
password string required
totp_code string optional Required if TOTP is enabled on the account

Response (Success)

NameTypeRequiredDescription
token string required
user object required

Example Request

curl -X POST "https://api.buddo.xyz/api/auth/login" \
  -H "Content-Type: application/json" \
  -d '{
  "email": "user@example.com",
  "password": "string",
  "totp_code": "string"
}'

Example Response

{
  "token": "string",
  "user": {
    "email": "user@example.com",
    "email_verified": false,
    "id": "00000000-0000-0000-0000-000000000000",
    "is_admin": false,
    "tier": "string",
    "totp_enabled": false,
    "username": "string"
  }
}
GET /api/auth/me

Get the authenticated user's full profile

Authentication

JWT Bearer Token

Response (Success)

NameTypeRequiredDescription
user object required

Example Request

curl -X GET "https://api.buddo.xyz/api/auth/me" \
  -H "Authorization: Bearer YOUR_JWT_TOKEN"

Example Response

{
  "user": {
    "email": "user@example.com",
    "email_verified": false,
    "id": "00000000-0000-0000-0000-000000000000",
    "points": 0,
    "referral_code": "string",
    "signup_multiplier": 0,
    "stats": {
      "connected_apps": 0,
      "direct_referrals": 0,
      "total_earned": 0,
      "total_spent": 0
    },
    "tier": "string",
    "tier_emoji": "string",
    "totp_enabled": false,
    "username": "string"
  }
}
POST /api/auth/register

Register a new user account

Creates a new user. Rate limited to 5 requests per hour per IP.

Authentication

None

Request Body

NameTypeRequiredDescription
email string (email) required
password string required
referral_code string optional Optional referral code
username string required

Response (Success)

NameTypeRequiredDescription
user object required

Example Request

curl -X POST "https://api.buddo.xyz/api/auth/register" \
  -H "Content-Type: application/json" \
  -d '{
  "email": "user@example.com",
  "password": "string",
  "referral_code": "string",
  "username": "string"
}'

Example Response

{
  "user": {
    "email": "user@example.com",
    "email_verified": false,
    "id": "00000000-0000-0000-0000-000000000000",
    "points": 0,
    "referral_code": "string",
    "registration_number": 0,
    "tier": "string",
    "username": "string"
  }
}
POST /api/auth/reset-password

Reset password using a reset token

Authentication

None

Request Body

NameTypeRequiredDescription
password string required
token string required

Response (Success)

NameTypeRequiredDescription
message string required

Example Request

curl -X POST "https://api.buddo.xyz/api/auth/reset-password" \
  -H "Content-Type: application/json" \
  -d '{
  "password": "string",
  "token": "string"
}'

Example Response

{
  "message": "string"
}
POST /api/auth/send-verification

Resend the email verification link

Authentication

JWT Bearer Token

Response (Success)

NameTypeRequiredDescription
message string required

Example Request

curl -X POST "https://api.buddo.xyz/api/auth/send-verification" \
  -H "Authorization: Bearer YOUR_JWT_TOKEN"

Example Response

{
  "message": "string"
}
POST /api/auth/totp/enable

Enable TOTP by confirming a valid code

Requires a valid TOTP code from the authenticator app. Returns recovery codes on success — these should be stored securely by the user.

Authentication

JWT Bearer Token

Request Body

NameTypeRequiredDescription
code string required 6-digit TOTP code from authenticator app

Response (Success)

NameTypeRequiredDescription
message string required
recovery_codes array<string> required

Example Request

curl -X POST "https://api.buddo.xyz/api/auth/totp/enable" \
  -H "Authorization: Bearer YOUR_JWT_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
  "code": "string"
}'

Example Response

{
  "message": "string",
  "recovery_codes": [
    "string"
  ]
}
POST /api/auth/totp/setup

Generate a TOTP secret and provisioning URI

Authentication

JWT Bearer Token

Response (Success)

NameTypeRequiredDescription
secret string required
uri string required

Example Request

curl -X POST "https://api.buddo.xyz/api/auth/totp/setup" \
  -H "Authorization: Bearer YOUR_JWT_TOKEN"

Example Response

{
  "secret": "string",
  "uri": "string"
}
POST /api/auth/totp/verify

Verify a TOTP or recovery code

Authentication

JWT Bearer Token

Request Body

NameTypeRequiredDescription
code string required 6-digit TOTP code or recovery code

Response (Success)

NameTypeRequiredDescription
message string required

Example Request

curl -X POST "https://api.buddo.xyz/api/auth/totp/verify" \
  -H "Authorization: Bearer YOUR_JWT_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
  "code": "string"
}'

Example Response

{
  "message": "string"
}
POST /api/auth/verify-email

Verify a user's email address with a token

Authentication

None

Request Body

NameTypeRequiredDescription
token string required

Response (Success)

NameTypeRequiredDescription
message string required

Example Request

curl -X POST "https://api.buddo.xyz/api/auth/verify-email" \
  -H "Content-Type: application/json" \
  -d '{
  "token": "string"
}'

Example Response

{
  "message": "string"
}
POST /api/oauth/apps

Register a new OAuth app

Creates a new OAuth app. Returns the client_secret — this is the only time it is shown. Rate limited to 3 requests per hour. **Requires email verification.** This endpoint is behind the `email_verified` pipeline. Your account email must be verified before you can register OAuth apps. If your email is not verified, this endpoint returns 403. To verify your email: call POST /api/auth/send-verification (requires JWT) to receive a verification code, then call POST /api/auth/verify-email with the code. After verification, retry this request with your JWT bearer token.

Authentication

JWT Bearer Token

Request Body

NameTypeRequiredDescription
allowed_scopes array<string> optional
app_description string optional
app_name string required
logo_url string optional
redirect_uris array<string> required
website_url string optional

Response (Success)

NameTypeRequiredDescription
app object required

Example Request

curl -X POST "https://api.buddo.xyz/api/oauth/apps" \
  -H "Authorization: Bearer YOUR_JWT_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
  "allowed_scopes": [
    "string"
  ],
  "app_description": "string",
  "app_name": "string",
  "logo_url": "string",
  "redirect_uris": [
    "string"
  ],
  "website_url": "string"
}'

Example Response

{
  "app": {
    "allowed_scopes": [
      "string"
    ],
    "app_description": "string",
    "app_name": "string",
    "client_id": "string",
    "id": "00000000-0000-0000-0000-000000000000",
    "inserted_at": "2026-01-01T00:00:00Z",
    "is_approved": false,
    "logo_url": {},
    "redirect_uris": [
      "string"
    ],
    "website_url": {},
    "client_secret": "string"
  }
}
GET /api/oauth/apps/{client_id}

Get public app metadata by client_id

Returns public app information. No authentication required.

Authentication

None

Path Parameters

NameInTypeRequiredDescription
client_id path string required The OAuth app's client_id

Response (Success)

NameTypeRequiredDescription
client_id string required
description string optional
name string required

Example Request

curl -X GET "https://api.buddo.xyz/api/oauth/apps/:client_id"

Example Response

{
  "client_id": "string",
  "description": "string",
  "name": "string"
}
GET /api/oauth/authorize

Request an authorization code

Issues an authorization code for the given client_id. Requires PKCE with S256 method. The code is valid for 600 seconds.

Authentication

JWT Bearer Token

Query Parameters

NameInTypeRequiredDescription
client_id query string required The OAuth app's client_id
response_type query "code" required Must be 'code'
redirect_uri query string optional Must match one of the app's registered redirect_uris
state query string optional Opaque value for CSRF protection — returned unchanged
scope query string optional Space-separated scopes (must be subset of app's allowed_scopes)
code_challenge query string required PKCE code challenge (BASE64URL(SHA256(code_verifier)))
code_challenge_method query "S256" required Must be 'S256' — plain is not supported

Response (Success)

NameTypeRequiredDescription
code string required
expires_in integer required Always 600 seconds
redirect_uri string required

Example Request

curl -X GET "https://api.buddo.xyz/api/oauth/authorize?client_id=VALUE&response_type=VALUE&code_challenge=VALUE&code_challenge_method=VALUE" \
  -H "Authorization: Bearer YOUR_JWT_TOKEN"

Example Response

{
  "code": "string",
  "expires_in": 0,
  "redirect_uri": "string"
}
GET /api/oauth/my-apps

List OAuth apps owned by the authenticated user

Authentication

JWT Bearer Token

Example Request

curl -X GET "https://api.buddo.xyz/api/oauth/my-apps" \
  -H "Authorization: Bearer YOUR_JWT_TOKEN"

Example Response

[
  {
    "allowed_scopes": [
      "string"
    ],
    "app_description": "string",
    "app_name": "string",
    "client_id": "string",
    "id": "00000000-0000-0000-0000-000000000000",
    "inserted_at": "2026-01-01T00:00:00Z",
    "is_approved": false,
    "logo_url": {},
    "redirect_uris": [
      "string"
    ],
    "website_url": {}
  }
]
PUT /api/oauth/my-apps/{id}

Update an OAuth app owned by the authenticated user

Authentication

JWT Bearer Token

Path Parameters

NameInTypeRequiredDescription
id path string (uuid) required The app's internal ID

Request Body

NameTypeRequiredDescription
allowed_scopes array<string> optional
app_description string optional
app_name string optional
logo_url string optional
redirect_uris array<string> optional
website_url string optional

Response (Success)

NameTypeRequiredDescription
allowed_scopes array<string> required
app_description string optional
app_name string required
client_id string required
id string (uuid) required
inserted_at string (date-time) optional
is_approved boolean required
logo_url string | null optional
redirect_uris array<string> required
website_url string | null optional

Example Request

curl -X PUT "https://api.buddo.xyz/api/oauth/my-apps/:id" \
  -H "Authorization: Bearer YOUR_JWT_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
  "allowed_scopes": [
    "string"
  ],
  "app_description": "string",
  "app_name": "string",
  "logo_url": "string",
  "redirect_uris": [
    "string"
  ],
  "website_url": "string"
}'

Example Response

{
  "allowed_scopes": [
    "string"
  ],
  "app_description": "string",
  "app_name": "string",
  "client_id": "string",
  "id": "00000000-0000-0000-0000-000000000000",
  "inserted_at": "2026-01-01T00:00:00Z",
  "is_approved": false,
  "logo_url": {},
  "redirect_uris": [
    "string"
  ],
  "website_url": {}
}
POST /api/oauth/my-apps/{id}/scope-request

Request additional scopes for an owned app

Submits a request to expand the app's allowed scopes. Requires admin approval. **Manual approval process:** Scope requests are reviewed manually by a Buddo admin — there is no automated approval. Approval times vary and there is no webhook or callback; poll GET /api/oauth/my-apps/{id}/scope-requests to check status. A `pending` status means the request is awaiting review. **deploy:manage is not auto-approved.** This scope grants full deployment management and requires explicit admin sign-off. Submit the request, then contact Buddo support to expedite review.

Authentication

JWT Bearer Token

Path Parameters

NameInTypeRequiredDescription
id path string (uuid) required The app's internal ID

Request Body

NameTypeRequiredDescription
requested_scopes array<string> required Scopes to add to the app's allowed_scopes

Response (Success)

NameTypeRequiredDescription
id string (uuid) required
inserted_at string (date-time) required
requested_scopes array<string> required
status string required

Example Request

curl -X POST "https://api.buddo.xyz/api/oauth/my-apps/:id/scope-request" \
  -H "Authorization: Bearer YOUR_JWT_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
  "requested_scopes": [
    "string"
  ]
}'

Example Response

{
  "id": "00000000-0000-0000-0000-000000000000",
  "inserted_at": "2026-01-01T00:00:00Z",
  "requested_scopes": [
    "string"
  ],
  "status": "string"
}
POST /api/oauth/token

Exchange an authorization code or refresh token for access tokens

Supports two grant types: 'authorization_code' (with PKCE code_verifier for public clients or client_secret for confidential clients) and 'refresh_token'. Authorization code grants also return a session_token for lightweight session maintenance.

Authentication

None

Request Body

One of the following:

Authorization Code Grant

NameTypeRequiredDescription
client_id string required
client_secret string optional Required for confidential clients (alternative to code_verifier)
code string required The authorization code received from /api/oauth/authorize
code_verifier string optional PKCE code verifier — required for public clients (no client_secret)
grant_type "authorization_code" required
redirect_uri string required Must match the redirect_uri used in the authorize request

Refresh Token Grant

NameTypeRequiredDescription
client_id string required
client_secret string required
grant_type "refresh_token" required
refresh_token string required

Response (Success)

NameTypeRequiredDescription
access_token string required
expires_in integer required
refresh_token string required
session_token string optional Short-lived session token — only present on authorization_code grants
session_token_expires_at string (date-time) optional Expiry of the session token — only present on authorization_code grants
token_type "Bearer" required

Example Request

curl -X POST "https://api.buddo.xyz/api/oauth/token" \
  -H "Content-Type: application/json" \
  -d '{
  "client_id": "string",
  "client_secret": "string",
  "code": "string",
  "code_verifier": "string",
  "grant_type": "authorization_code",
  "redirect_uri": "string"
}'

Example Response

{
  "access_token": "string",
  "expires_in": 0,
  "refresh_token": "string",
  "session_token": "string",
  "session_token_expires_at": "2026-01-01T00:00:00Z",
  "token_type": "Bearer"
}
POST /api/oauth/token/verify

Introspect an access token

Returns token validity and metadata. Always returns 200 — check the 'active' field. No authentication required.

Authentication

None

Request Body

NameTypeRequiredDescription
token string required The access token to verify

Response (Success)

NameTypeRequiredDescription
active boolean required
app_id string (uuid) optional
expires_at string (date-time) optional
reason string optional Present when active is false (e.g. 'expired')
scopes array<string> optional
user_id string (uuid) optional

Example Request

curl -X POST "https://api.buddo.xyz/api/oauth/token/verify" \
  -H "Content-Type: application/json" \
  -d '{
  "token": "string"
}'

Example Response

{
  "active": false,
  "app_id": "00000000-0000-0000-0000-000000000000",
  "expires_at": "2026-01-01T00:00:00Z",
  "reason": "string",
  "scopes": [
    "string"
  ],
  "user_id": "00000000-0000-0000-0000-000000000000"
}
POST /api/session/refresh

Refresh a session token

Validates the current session token, sends a heartbeat, and returns a rotated token. The old token is invalidated atomically. Rate limited to 20 requests per minute per IP. Does not use JWT — authenticates via the session_token in the request body.

Authentication

None

Request Body

NameTypeRequiredDescription
session_token string required The current session token to refresh

Response (Success)

NameTypeRequiredDescription
expires_at string (date-time) required
session_token string required

Example Request

curl -X POST "https://api.buddo.xyz/api/session/refresh" \
  -H "Content-Type: application/json" \
  -d '{
  "session_token": "string"
}'

Example Response

{
  "expires_at": "2026-01-01T00:00:00Z",
  "session_token": "string"
}