Endpoints
gt.Mount(app, "/auth") registers three groups of routes. All paths below assume the /auth prefix.
Typed JSON endpoints
These bind and validate a request struct, forward the original body, and pass GoTrue's body back unchanged. The request and response types document the endpoint.
The request types describe GoTrue's parameters for the OpenAPI document and for validation. They do not filter: once the body validates, the client's original JSON is what GoTrue receives. A parameter ezz does not model still arrives, and an explicit false such as "create_user": false is kept rather than dropped. Booleans that GoTrue defaults to true are *bool in the structs for the same reason.
| Method and path | Request type | Response type | Rate limited |
|---|---|---|---|
GET /health | none | HealthResponse | no |
GET /settings | none | SettingsResponse | no |
POST /signup | SignupRequest | SessionResponse | yes |
POST /token | TokenRequest | SessionResponse | yes |
POST /otp | OTPRequest | MessageResponse | yes |
POST /verify | VerifyRequest | SessionResponse | no |
POST /recover | RecoverRequest | MessageResponse | yes |
POST /resend | ResendRequest | MessageResponse | yes |
POST /logout | none | MessageResponse | no |
GET /user | none | UserObject | no |
PUT /user | UpdateUserRequest | UserObject | no |
POST /reauthenticate | ReauthenticateRequest | MessageResponse | no |
Sign up
type SignupRequest struct {
Email string `json:"email,omitempty" validate:"omitempty,email"`
Phone string `json:"phone,omitempty"`
Password string `json:"password" validate:"required,min=6"`
Data map[string]any `json:"data,omitempty"`
Channel string `json:"channel,omitempty"`
CodeChallenge string `json:"code_challenge,omitempty"`
CodeChallengeMethod string `json:"code_challenge_method,omitempty"`
MetaSecurity *MetaSecurity `json:"gotrue_meta_security,omitempty"`
}
curl -s localhost:8080/auth/signup \
-H 'Content-Type: application/json' \
-d '{"email":"ada@example.com","password":"password123","data":{"name":"Ada"}}'
Get a token
The grant is selected with the grant_type query parameter, which is forwarded to GoTrue along with the rest of the query string.
type TokenRequest struct {
Email string `json:"email,omitempty" validate:"omitempty,email"` // password
Phone string `json:"phone,omitempty"` // password
Password string `json:"password,omitempty"` // password
RefreshToken string `json:"refresh_token,omitempty"` // refresh_token
AuthCode string `json:"auth_code,omitempty"` // pkce
CodeVerifier string `json:"code_verifier,omitempty"` // pkce
IDToken string `json:"id_token,omitempty"` // id_token
AccessToken string `json:"access_token,omitempty"` // id_token
Nonce string `json:"nonce,omitempty"` // id_token
Provider string `json:"provider,omitempty"` // id_token
ClientID string `json:"client_id,omitempty"` // id_token
Issuer string `json:"issuer,omitempty"` // id_token
LinkIdentity *bool `json:"link_identity,omitempty"` // id_token
MetaSecurity *MetaSecurity `json:"gotrue_meta_security,omitempty"`
}
# password grant
curl -s 'localhost:8080/auth/token?grant_type=password' \
-H 'Content-Type: application/json' \
-d '{"email":"ada@example.com","password":"password123"}'
# refresh grant
curl -s 'localhost:8080/auth/token?grant_type=refresh_token' \
-H 'Content-Type: application/json' \
-d '{"refresh_token":"..."}'
# pkce grant: exchange the code from a magic link or OAuth redirect
curl -s 'localhost:8080/auth/token?grant_type=pkce' \
-H 'Content-Type: application/json' \
-d '{"auth_code":"...","code_verifier":"..."}'
A successful response is a SessionResponse with access_token, token_type, expires_in, expires_at, refresh_token, the user object, and weak_password.
Read and update the current user
Both require the caller's bearer token, which the proxy forwards as-is.
curl -s localhost:8080/auth/user -H "Authorization: Bearer $TOKEN"
curl -s -X PUT localhost:8080/auth/user \
-H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' \
-d '{"data":{"name":"Ada Lovelace"}}'
Redirect endpoints
Some GoTrue endpoints answer with redirects or HTML rather than JSON, so they are proxied byte for byte through a reverse proxy instead of a typed handler.
| Method and path | Purpose |
|---|---|
GET /authorize | Start an external OAuth flow |
GET /callback | External provider callback |
GET /verify | Email link verification |
GET /oauth/authorize | OAuth2 server authorization |
GET /verify and POST /verify are separate routes: the GET form is the link a user clicks in an email and redirects, while the POST form takes a JSON body and returns a session.
Point browsers at these directly:
<a href="/auth/authorize?provider=github">Sign in with GitHub</a>
If the proxy cannot reach GoTrue, these routes return 502 with the standard JSON error body.
OAuth2 server
Mounted unconditionally. GoTrue decides whether the feature is on, and returns its own error when it is not.
| Method and path | Request type | Response type | Rate limited |
|---|---|---|---|
GET /.well-known/oauth-authorization-server | none | OAuthServerMetadata | no |
GET /.well-known/openid-configuration | none | OAuthServerMetadata | no |
GET /.well-known/jwks.json | none | JWKSResponse | no |
GET /oauth/authorize | redirect passthrough | — | no |
POST /oauth/token | OAuthTokenRequest | OAuthTokenResponse | yes |
POST /oauth/clients/register | ClientRegistrationRequest | ClientRegistrationResponse | yes |
GET /oauth/userinfo | none | OAuthUserInfo | no |
GOTRUE_OAUTH_SERVER_ALLOW_DYNAMIC_REGISTRATION=true, anyone who can reach /auth/oauth/clients/register can create an OAuth client. ezz rate limits the route, but if you do not need public registration, turn the setting off in GoTrue.Passkeys and WebAuthn
Also mounted unconditionally.
| Method and path | Request type | Response type | Rate limited |
|---|---|---|---|
GET /passkeys | none | PasskeyListResponse | no |
POST /passkeys/registration/options | PasskeyRegistrationOptionsRequest | PasskeyRegistrationOptionsResponse | no |
POST /passkeys/registration/verify | PasskeyRegistrationVerifyRequest | PasskeyRegistrationVerifyResponse | no |
POST /passkeys/authentication/options | PasskeyAuthenticationOptionsRequest | PasskeyAuthenticationOptionsResponse | yes |
POST /passkeys/authentication/verify | PasskeyAuthenticationVerifyRequest | SessionResponse | yes |
PATCH /passkeys/{id} | PasskeyUpdateRequest | PasskeyRegistrationVerifyResponse | no |
DELETE /passkeys/{id} | none | MessageResponse | no |
The two {id} routes forward the inbound path rather than a fixed one, so the identifier is validated first. It must be a single non-empty segment with no slashes and no dot-dot components; anything else is rejected with 400 before the request leaves your process. Both share one rate-limit bucket per client, keyed by the route template rather than the concrete ID.
Browsers must perform WebAuthn against the public origin, which means GOTRUE_WEBAUTHN_RP_ORIGINS has to include your ezz origin. See Deployment.
Route metadata
Mounted routes carry tags so the docs group them sensibly: Auth for the core endpoints, OAuth for the OAuth2 server, and Passkey for WebAuthn. They are all registered Public() at the ezz layer, since GoTrue performs its own bearer-token checks. They appear in /openapi.json and the Scalar UI next to your own routes.
Next steps
- Client IP and rate limits for which requests get throttled and how the key is derived.
- Deployment for the GoTrue configuration this expects.