/auth/v1/* on your project URL. Every endpoint accepts the project’s Anon Key (or, for admin endpoints, the Service Role Key) as both the apikey and Authorization: Bearer headers, except where noted (e.g., after sign-in, the user’s access token replaces the Anon Key in Authorization).
For end-to-end signup/signin flows, see Signup, signin, magic link. For OAuth, see OAuth providers. For the conceptual model, see Auth model.
Common headers
Two header sets you’ll use depending on whether the user is signed in: Unauthenticated requests (signup, signin, recovery, OAuth initiation):/user, /logout, MFA enrollment, etc.):
/admin/users/*):
Signup
POST /auth/v1/signup
Create a new user with email + password (or phone + password if phone auth is enabled). On defaultautoConfirm: true, returns a session immediately. On autoConfirm: false, returns the user record only; the user must verify their email via the link sent by GoTrue.
Email address. Either
email or phone is required.E.164 phone number (e.g.,
+14155552671). Requires GOTRUE_EXTERNAL_PHONE_ENABLED=true and an SMS provider configured.At least 6 characters by GoTrue default.
Arbitrary key/value pairs to store in
user_metadata. User-editable.{ captcha_token: "..." } if CAPTCHA is enabled.Signin
POST /auth/v1/token?grant_type=password
Exchange email/password (or phone/password) for an access token + refresh token.Must be
password.Either
email or phone is required.E.164 format. Requires phone auth enabled.
POST /auth/v1/token?grant_type=refresh_token
Exchange a refresh token for a new access token + new refresh token. Refresh-token rotation is enabled by default — each refresh token is single-use, with a 10-second grace window for concurrent refresh attempts.POST /auth/v1/token?grant_type=pkce
Exchange a PKCE authorization code (from OAuth or magic link) for a session.Authorization code from the redirect query string.
The PKCE verifier you generated before calling
/authorize.Passwordless / magic link
POST /auth/v1/otp
Send a one-time email (or SMS) with a sign-in link. The user clicks it, GoTrue redirects them back to your app with tokens in the URL fragment.Either
email or phone is required.E.164 format. Requires phone auth enabled.
Default
true. When false, returns 400 if no user with that address exists — useful for “magic link only for existing users.”{ email_redirect_to: "...", data: { ... } } — email_redirect_to overrides the default site URL for this request; data populates user_metadata if create_user results in a new user.200 OK with empty body if the email was queued. Returns 200 even for non-existent addresses when create_user: false would have failed — GoTrue treats this as “do not enumerate users.”
POST /auth/v1/verify
Verify an OTP token directly (alternative to clicking the email link). Useful for native apps that handle the email link via a URL scheme.signup, magiclink, recovery, invite, email_change, sms, or phone_change.The token from the email link or SMS.
Required for email-typed verifications.
Required for SMS verifications.
POST /token?grant_type=password.
Password recovery
POST /auth/v1/recover
Send a password-reset email. The user clicks it and arrives at yourredirect_to URL signed in (tokens in URL fragment), then calls PUT /user to set a new password.
{ redirect_to: "https://your-app.example.com/auth/reset-password" } overrides the default site URL for this request.OAuth
GET /auth/v1/authorize
Initiates an OAuth flow. Returns a 302 redirect to the upstream provider. Not callable from cURL in the normal sense — you put the user’s browser at this URL.One of:
apple, azure, bitbucket, discord, facebook, figma, github, gitlab, google, kakao, keycloak, linkedin_oidc, notion, slack, slack_oidc, spotify, twitch, twitter, workos, zoom. Must be enabled on the project.Where to redirect after the OAuth dance completes. Must be in the project’s
uriAllowList.Space-separated extra scopes to request from the provider.
PKCE code challenge (base64url-encoded SHA-256 of the verifier). Including this puts the flow in PKCE mode — the code comes back in the query string instead of the URL fragment.
Must be
S256 when code_challenge is set.GET /auth/v1/callback
GoTrue’s own OAuth callback. The upstream provider redirects to this URL after the user authorizes; GoTrue exchanges the code, finalizes the session, then 302s the browser to yourredirect_to. You shouldn’t call this directly — it’s the URL you register with the provider.
User management (authenticated)
GET /auth/v1/user
Return the currently-signed-in user. Read from the access token’s claims plus a fresh lookup againstauth.users.
PUT /auth/v1/user
Update the signed-in user’s email, password, phone, oruser_metadata. Cannot modify app_metadata from here (use the admin API).
Triggers a confirmation email if changed. The new email isn’t active until confirmed; the session continues under the old email until then.
The new password.
Same flow as email — sends a verification SMS.
Merged into
user_metadata.POST /auth/v1/logout
Invalidate the current session (revokes the refresh token server-side). Optionally specify scope.global (default — revoke all refresh tokens for this user), local (just this session), or others (every session except this one).Multi-factor authentication
TOTP MFA is enabled by default; phone-based MFA requiresGOTRUE_MFA_PHONE_ENROLL_ENABLED=true and Twilio configured. Up to 10 factors per user.
POST /auth/v1/factors
Enroll a new MFA factor. Returns a TOTP secret (and QR code URI) the user can add to their authenticator app.totp or phone.User-visible label, e.g., “iPhone Authy”.
TOTP issuer field, e.g., your app name.
POST /auth/v1/factors//challenge
Start a challenge (TOTP doesn’t need this; phone sends the OTP).POST /auth/v1/factors//verify
Verify the challenge code. On first-time enrollment, also activates the factor. Returns anaal2 (Authenticator Assurance Level 2) access token if successful.
DELETE /auth/v1/factors/
Unenroll a factor. Requires the current access token to be at aal2 if the factor being deleted is the user’s last factor — prevents lockout from a stolen access token.Admin (service-role only)
These require the Service Role Key, not the user’s access token. Server-side use only.GET /auth/v1/admin/users
List all users in the project. Supports pagination viapage and per_page (default 50).
POST /auth/v1/admin/users
Create a user with any email, password, metadata. Skips confirmation. Useful for migrations.Default
true.Default
true.The only way to set
app_metadata.Override the default
authenticated role.GET /auth/v1/admin/users/
Fetch a specific user, including the fieldsGET /user doesn’t return (banned status, last sign-in, MFA factors, identities).
PUT /auth/v1/admin/users/
Update any field on the user, includingapp_metadata, ban_duration, and role. The right place to set custom claims that policies will read via auth.jwt().
24h, 48h, none, etc. Banned users get 401 on sign-in.DELETE /auth/v1/admin/users/
Hard-delete a user. Cascades through identities, sessions, MFA factors, and (if configured) theauth.users row’s downstream references in public.*.
POST /auth/v1/admin/generate_link
Generate a magic-link URL without sending an email. Useful for impersonation flows or custom email delivery.signup, invite, magiclink, recovery, email_change_current, email_change_new.{ "action_link": "...", "email_otp": "...", "hashed_token": "...", ... }.
Error Responses
GoTrue returns errors as{"error": "code", "error_description": "human-readable"} or {"msg": "..."} depending on the endpoint. Common codes:
| Status | Code | When |
|---|---|---|
| 400 | invalid_grant | Wrong email/password, expired refresh token, or refresh-token already used |
| 400 | email_not_confirmed | Sign-in attempt before email verification |
| 400 | email_address_invalid | Malformed email |
| 400 | weak_password | Below 6 characters by default |
| 400 | user_already_exists | Signup with an existing email |
| 401 | unauthorized | Missing or expired access token |
| 403 | not_admin | Hitting /admin/* without the service role key |
| 422 | invalid_credentials | Same as 400 invalid_grant in some GoTrue versions |
| 429 | over_email_send_rate_limit | Too many email-sending attempts (30/hour by default) |
| 429 | over_sms_send_rate_limit | Too many SMS attempts |
| 429 | over_request_rate_limit | Too many failed verify attempts |
/admin/* endpoints additionally return:
| Status | Code | When |
|---|---|---|
| 404 | user_not_found | User UUID doesn’t exist |
| 422 | validation_failed | Body field shape is wrong (e.g., non-string phone) |
Next steps
Signup, signin, magic link
End-to-end flows in Python, TypeScript, and cURL.
OAuth providers
Provider-specific configuration + PKCE.
Auth model
JWT structure, the four roles, refresh-token rotation, the autoconfirm default.
RLS Cookbook
How to use auth.uid() and auth.jwt() in policies on the tables your users will hit.