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 it, and pass GoTrue's body back unchanged. The response type is used to document the endpoint.
| 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"`
}
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"`
Phone string `json:"phone,omitempty"`
Password string `json:"password,omitempty"`
RefreshToken string `json:"refresh_token,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":"..."}'
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.