Public auth API
These are the endpoints your application uses for sign-in, registration, PKCE token exchange, refresh rotation, logout, and current-user lookup. Dashboard and service APIs are intentionally excluded from this reference.
Base rules
Every endpoint below is served by the public Passport Auth web container.
Hosted and custom flows send a SHA-256 code challenge, then exchange with the verifier.
redirect_url must match one configured Redirect URL, except localhost in development.
Content-Type: application/json
Authorization: Bearer public_access_token # only for GET /me
/api/v1/auth/request/validate
Validate a hosted-page or custom-page request before showing a login UI.
Query
redirect_urlRequired. App callback URL that should receive the auth code.code_challengeRequired. PKCE SHA-256 challenge, 32-256 chars.
200 response
{
"ok": true,
"redirect_url": "https://app.example.com/auth/callback"
}
Password registration and login
/api/v1/auth/register
Start password registration. Passport Auth stores a pending registration, sends an email OTP, and does not create the user until verification succeeds.
Request body
nameRequired. Display name, 1-120 chars. Normalized to title case.emailRequired. User email, normalized to lowercase.passwordRequired. Minimum 12 chars.redirect_urlRequired. Exact allowed callback URL.code_challengeRequired. PKCE challenge for the later token exchange.
200 response
{
"sent": true,
"dev_otp": "482913",
"dev_token": null,
"dev_magic_link": null
}
dev_otp is only returned outside production.
/api/v1/auth/register/verify
Verify the registration OTP, create the user, mark email verified, and issue an authorization code.
Request body
{
"email": "[email protected]",
"otp": "482913"
}
200 response
{
"authorization_code": "pa_code_...",
"redirect_url": "https://app.example.com/auth/callback"
}
/api/v1/auth/password/login
Validate email and password for an existing active user, then issue an authorization code.
Request body
{
"email": "[email protected]",
"password": "correct-horse-battery-staple",
"redirect_url": "https://app.example.com/auth/callback",
"code_challenge": "S256_challenge"
}
200 response
{
"authorization_code": "pa_code_...",
"redirect_url": "https://app.example.com/auth/callback"
}
One-time passcode login
/api/v1/auth/otp/start
Send a login OTP to the supplied email. If auto-create is enabled for OTP, verification can create the user.
{
"email": "[email protected]",
"redirect_url": "https://app.example.com/auth/callback",
"code_challenge": "S256_challenge"
}
200 response
{ "sent": true, "dev_otp": "482913" }
/api/v1/auth/otp/verify
Verify the OTP and issue an authorization code for the configured redirect URL.
{
"email": "[email protected]",
"otp": "482913",
"redirect_url": "https://app.example.com/auth/callback",
"code_challenge": "S256_challenge"
}
Magic link login
/api/v1/auth/magic-link/start
Send a secure email link. The link opens Passport Auth, consumes the token, and returns the app to its callback with a code.
{
"email": "[email protected]",
"redirect_url": "https://app.example.com/auth/callback",
"code_challenge": "S256_challenge"
}
200 response
{
"sent": true,
"dev_magic_link": "/verify?token=..."
}
/api/v1/auth/magic-link/consume
Consume a magic-link token directly. This is mostly useful for custom verification pages.
{ "token": "magic_link_token" }
200 response
{
"authorization_code": "pa_code_...",
"redirect_url": "https://app.example.com/auth/callback"
}
Password reset OTP
/api/v1/auth/password-reset/start
Send a reset code if the user exists. The response is intentionally generic to avoid account enumeration.
{ "email": "[email protected]" }
200 response
{ "sent": true }
/api/v1/auth/password-reset/confirm
Verify the reset OTP and replace the user's password.
{
"email": "[email protected]",
"otp": "482913",
"password": "new-correct-horse-battery-staple"
}
200 response
{ "ok": true }
Google OAuth
/api/v1/auth/google/start
Create a Google authorization URL after validating the configured redirect URL and PKCE challenge.
Query
redirect_url=https://app.example.com/auth/callback
code_challenge=S256_challenge
200 response
{ "authorization_url": "https://accounts.google.com/o/oauth2/v2/auth?..." }
/api/v1/auth/google/callback
Google returns here. Passport Auth consumes the OAuth state, creates or updates the user using Google's email and name, then redirects back with ?code=.
Query
state=oauth_state
code=google_provider_code
response=redirect | json
Token exchange and sessions
/api/v1/auth/token
Exchange an authorization code and PKCE verifier for a short-lived access token and a rotating refresh token.
Request body
{
"code": "pa_code_...",
"code_verifier": "original_pkce_verifier"
}
200 response
{
"access_token": "jwt...",
"refresh_token": "opaque_refresh_token",
"token_type": "bearer",
"expires_in": 7776000,
"user": {
"id": "user_id",
"name": "Jane Appleseed",
"email": "[email protected]",
"role": "user",
"email_verified": true,
"user_metadata": {}
}
}
/api/v1/auth/refresh
Rotate a refresh token and return a new token pair. Replaying an old refresh token returns 401.
{ "refresh_token": "opaque_refresh_token" }
/api/v1/auth/logout
Revoke the current refresh token. Your app should also clear local tokens.
{ "refresh_token": "opaque_refresh_token" }
200 response
{ "ok": true }
/api/v1/auth/me
Return the current public auth user for the supplied access token.
Headers
Authorization: Bearer public_access_token
200 response
{
"id": "user_id",
"name": "Jane Appleseed",
"email": "[email protected]",
"role": "user",
"email_verified": true,
"user_metadata": {
"plan": "pro",
"subscription_status": "active"
}
}
Errors
Invalid OTP, expired code, redirect mismatch, bad OAuth state, or malformed input.
Invalid password, expired refresh token, missing bearer token, or replayed refresh token.
User is blocked or deactivated. The response detail can include the configured block message.
The requested auth method is disabled in dashboard settings.
A user with the same email already exists during registration.
Email or provider configuration is unavailable, for example Resend or Google OAuth is not configured.