HelloJohn / docs
API Reference

Authentication API

REST API endpoints for sign-in, sign-up, sign-out, token refresh, magic links, and OAuth.

Authentication API

Endpoints for user authentication. Most endpoints accept a publishable key (pk_live_...) in the Authorization header and require X-Tenant-ID.

POST /v1/auth/sign-up

Register a new user with email and password.

Headers:

HeaderRequiredValue
AuthorizationBearer pk_live_...
X-Tenant-IDTenant ID
Content-Typeapplication/json

Body:

FieldTypeRequiredDescription
emailstringUser's email address
passwordstringPassword (min 8 chars)
namestringFull name
usernamestringUnique username (if enabled)
metadataobjectCustom public_metadata

Responses:

  • 201 Created — User created, session issued
  • 409 Conflictemail_already_exists
  • 422 Unprocessablepassword_too_weak, invalid_email
curl -X POST https://api.hellojohn.dev/v1/auth/sign-up \
  -H "Authorization: Bearer pk_live_abc123" \
  -H "X-Tenant-ID: tnt_01HABCDEF654321" \
  -H "Content-Type: application/json" \
  -d '{
    "email": "alice@example.com",
    "password": "s3cur3P@ssw0rd",
    "name": "Alice Smith"
  }'

Response:

{
  "user": {
    "id": "usr_01HABCDEF123456",
    "email": "alice@example.com",
    "name": "Alice Smith",
    "email_verified": false,
    "created_at": "2024-01-15T10:30:00Z"
  },
  "session": {
    "id": "ses_01HABCDEF999888",
    "access_token": "eyJhbGciOiJFZERTQSJ9...",
    "refresh_token": "rft_01HABCDEF777666",
    "access_token_expires_at": "2024-01-15T11:30:00Z",
    "refresh_token_expires_at": "2024-02-14T10:30:00Z"
  }
}

POST /v1/auth/sign-in

Sign in with email and password.

Body:

FieldTypeRequiredDescription
emailstringUser's email
passwordstringUser's password
captcha_tokenstringCaptcha token if bot protection is enabled

Responses:

  • 200 OK — Returns user + session (same shape as sign-up)
  • 401 Unauthorizedinvalid_credentials
  • 403 Forbiddenmfa_required (see below), account_locked
  • 429 Too Many Requestsrate_limit_exceeded
curl -X POST https://api.hellojohn.dev/v1/auth/sign-in \
  -H "Authorization: Bearer pk_live_abc123" \
  -H "X-Tenant-ID: tnt_01HABCDEF654321" \
  -H "Content-Type: application/json" \
  -d '{"email": "alice@example.com", "password": "s3cur3P@ssw0rd"}'

MFA Required Response

When MFA is required, the server returns 403 with a challenge token:

{
  "error": {
    "code": "mfa_required",
    "status": 403,
    "mfa_challenge": {
      "challenge_id": "chg_01HABCDEF555444",
      "factor_type": "totp",
      "expires_at": "2024-01-15T10:35:00Z"
    }
  }
}

Use challenge_id with POST /v1/auth/mfa/verify to complete authentication.


POST /v1/auth/sign-out

Revoke the current session.

Headers:

HeaderRequiredValue
AuthorizationBearer <access_token>
curl -X POST https://api.hellojohn.dev/v1/auth/sign-out \
  -H "Authorization: Bearer eyJhbGciOiJFZERTQSJ9..."

Response: 204 No Content


POST /v1/auth/token/refresh

Exchange a refresh token for a new access token. Implements refresh token rotation — the old refresh token is invalidated and a new one is issued.

Body:

FieldTypeRequiredDescription
refresh_tokenstringCurrent refresh token
curl -X POST https://api.hellojohn.dev/v1/auth/token/refresh \
  -H "Authorization: Bearer pk_live_abc123" \
  -H "X-Tenant-ID: tnt_01HABCDEF654321" \
  -H "Content-Type: application/json" \
  -d '{"refresh_token": "rft_01HABCDEF777666"}'

Response:

{
  "access_token": "eyJhbGciOiJFZERTQSJ9...",
  "refresh_token": "rft_01HABCDEF888777",
  "access_token_expires_at": "2024-01-15T12:30:00Z",
  "refresh_token_expires_at": "2024-02-14T11:30:00Z"
}

POST /v1/auth/magic-link

Send a magic link email to the user. The link expires in 15 minutes by default.

Body:

FieldTypeRequiredDescription
emailstringUser's email address
redirect_urlstringURL to redirect after clicking the link
create_if_not_existsbooleanRegister user if they don't exist (default: false)
curl -X POST https://api.hellojohn.dev/v1/auth/magic-link \
  -H "Authorization: Bearer pk_live_abc123" \
  -H "X-Tenant-ID: tnt_01HABCDEF654321" \
  -H "Content-Type: application/json" \
  -d '{
    "email": "alice@example.com",
    "redirect_url": "https://app.example.com/auth/callback"
  }'

Response: 200 OK

{ "sent": true }

POST /v1/auth/magic-link/verify

Verify a magic link token (called automatically via the redirect URL).

Body:

FieldTypeRequiredDescription
tokenstringToken from the magic link URL

Response: Same shape as sign-in — returns user + session.


POST /v1/auth/mfa/verify

Complete MFA verification during sign-in.

Body:

FieldTypeRequiredDescription
challenge_idstringFrom the mfa_required error response
codestringTOTP code, OTP, or backup code
factor_typestringtotp, sms, email_otp, backup_code
curl -X POST https://api.hellojohn.dev/v1/auth/mfa/verify \
  -H "Authorization: Bearer pk_live_abc123" \
  -H "X-Tenant-ID: tnt_01HABCDEF654321" \
  -H "Content-Type: application/json" \
  -d '{
    "challenge_id": "chg_01HABCDEF555444",
    "code": "847293",
    "factor_type": "totp"
  }'

Response: Same shape as sign-in — returns user + session.


POST /v1/auth/password/forgot

Trigger a password reset email.

Body:

FieldTypeRequiredDescription
emailstringUser's email
redirect_urlstringURL to redirect after clicking the link

Response: 200 OK — Always returns success, even if email doesn't exist (prevents enumeration).

{ "sent": true }

POST /v1/auth/password/reset

Set a new password using a reset token.

Body:

FieldTypeRequiredDescription
tokenstringToken from reset email
passwordstringNew password

Response: 200 OK — Returns user + session.


GET /v1/auth/me

Return the current authenticated user.

Headers: Authorization: Bearer <access_token>

curl https://api.hellojohn.dev/v1/auth/me \
  -H "Authorization: Bearer eyJhbGciOiJFZERTQSJ9..."

Response:

{
  "id": "usr_01HABCDEF123456",
  "email": "alice@example.com",
  "name": "Alice Smith",
  "email_verified": true,
  "mfa_enabled": true,
  "role": "member",
  "public_metadata": {},
  "created_at": "2024-01-15T10:30:00Z",
  "updated_at": "2024-01-15T10:30:00Z"
}

OAuth Endpoints

See OAuth API for the full OAuth 2.0 flow endpoints.

On this page