//Auth API

Authentication API

Endpoints

POST /api/auth/login

Authenticates a user and returns a JWT access token and user object.

Input: ~~~json { "email": "user@example.com", "password": "yourpassword", "org_name": "your-organization-name" } ~~~

Output: ~~~json { "access_token": "jwt_token_string", "user": { "id": 1, "email": "user@example.com" } } ~~~

POST /api/auth/otp

Sends a one-time password (OTP).

Input: ~~~json { "email": "user@example.com", "app_uuid": "" } ~~~

Output: ~~~json "email sent successfully" ~~~

POST /api/auth/magic-link/send

Sends a magic-link code to the given email. No authentication required.

Input: ~~~json { "email": "user@example.com", "org_uuid": "ab8db11a-...", "redirect_to": "https://app.example.com/callback" } ~~~

| Field | Required | Description | |---|---|---| | email | Yes | The user's email address | | org_uuid | No | Organization UUID (enables JIT user creation under this org) | | redirect_to | No | URL returned in the verify response for frontend redirect |

Output: ~~~json { "sent": true, "dev_token": null, "expires_in_seconds": 900 } ~~~

> dev_token is only populated when BUTTRBASE_MAGIC_LINK_DEV_ECHO=1 is set (dev/staging environments).

POST /api/auth/magic-link/verify

Verifies the magic-link token and returns a JWT access token. If no user exists for the email, one is created automatically (JIT provisioning).

Input: ~~~json { "token": "base64url-encoded-token-from-email" } ~~~

Output: ~~~json { "access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6...", "token_type": "Bearer", "user": { "user_uuid": "550e8400-e29b-41d4-a716-446655440000", "email": "user@example.com" }, "redirect_to": "https://app.example.com/callback" } ~~~

JWT claims: ~~~json { "sub": "user-uuid", "org": "org-uuid", "aud": "org-name", "scope": [], "iss": "https://api.buttrbase.com", "jti": "unique-token-id", "exp": 1717200000, "iat": 1717113600 } ~~~

| Claim | Description | |---|---| | sub | User UUID | | org | Organization UUID | | aud | Organization name (used by downstream services to validate audience) | | scope | Reserved for future RBAC scopes | | iss | Issuer URL of the ButtrBase instance | | exp | Expiry (24 hours from issue) |

SDK Examples

Python

~~~python from buttrbase import ButtrbaseClient

client = ButtrbaseClient(api_key="your-key") client.send_magic_link("user@example.com", redirect_to="https://app.example.com") resp = client.verify_magic_link("token-from-email") print(resp["access_token"]) ~~~

Node.js / TypeScript

~~~typescript import { ButtrbaseClient } from '@buttrbase/sdk';

const client = new ButtrbaseClient({ apiKey: 'your-key' }); await client.sendMagicLink('user@example.com', { redirectTo: 'https://app.example.com' }); const resp = await client.verifyMagicLink('token-from-email'); console.log(resp.accessToken); ~~~

Go

~~~go client := buttrbase.New("your-key") _, err := client.SendMagicLink(ctx, "user@example.com", &buttrbase.SendMagicLinkOptions{RedirectURL: "https://app.example.com"}) resp, err := client.VerifyMagicLink(ctx, "token-from-email") fmt.Println(resp.AccessToken) ~~~

Rust

~~~rust let client = ButtrbaseClient::new("your-key"); client.magic_link_send("user@example.com", Some("https://app.example.com")).await?; let login = client.magic_link_verify("token-from-email").await?; println!("{}", login.access_token); ~~~

Error Reference

| Status | Code | Meaning | |---|---|---| | 400 | bad_request | Missing or invalid email | | 401 | unauthorized | Token is invalid, expired, or already used | | 500 | internal | Server error (e.g. email delivery failure) |