Auth & Register Endpoints
Auth + register endpoints, smart-linking, C1 fix
Auth & Register Endpoints
This page covers the implementation and behavior of the authentication and registration endpoints, specifically POST /auth/register and GET /auth/callback. It details rate limiting, user creation strategies across environments, session handling, user metadata updates, and the smart-linking mechanism that connects verified users to pre-existing client records.
Register Endpoint
The POST /auth/register endpoint, defined in src/app/api/auth/register/route.ts, handles new user registrations. It expects email, password, name, and type in the request body.
Rate limiting is enforced using getRegisterLimiter() from src/lib/ratelimit.ts. The client's IP is extracted via getIp(req) and checked against the rate limit. If exceeded, a 429 status is returned with the message "Muitas tentativas de registro. Aguarde um momento.".
User creation differs by environment:
- In
production,supabase.auth.signUp()is used with the anon key. This triggers Supabase’s email verification flow. The response’sdata.sessiondetermines whetherrequiresEmailConfirmationis set totrue(if no session is returned). - In
development, the service roleadminClient.auth.admin.createUser()is used withemail_confirm: true. This creates a confirmed user directly, bypassing email verification for faster iteration.
The endpoint returns { success: true, type, requiresEmailConfirmation } on success. Errors during registration return a 400 status with the Supabase error message.
Callback Endpoint
The GET /auth/callback endpoint, located in src/app/auth/callback/route.ts, handles post-authentication redirects from Supabase, such as after email verification or password recovery.
The origin is constructed using x-forwarded-host and x-forwarded-proto headers to support correct redirection in proxy environments like Vercel.
Key behaviors:
- Session Exchange: The
codequery parameter is exchanged for a session viasupabase.auth.exchangeCodeForSession(code). - Password Recovery: If
type=recovery, the user is redirected to/reset-password. - User Metadata Update: If
typeis"professional"or"client",supabase.auth.updateUser({ data: { type } })sets the user type in metadata. - Smart-linking: After successful session exchange and only if
type="client", the endpoint performs a database update. It links the authenticateduser.idto anyclientsrecords with a matchingemailandnulluserId, usingdb.update(clients).set({ userId: user.id })with a condition onisNull(clients.userId)andeq(clients.email, user.email).
On success, the user is redirected to /auth/redirect. If the session exchange fails, they are redirected to /login?error=auth.
Known Gaps
In src/app/api/auth/register/route.ts, the use of adminClient.auth.admin.createUser() in development with email_confirm: true bypasses email verification for faster testing. However, this method does not trigger actual email delivery even when email_confirm is false. As a result, the development environment does not replicate the production email verification flow, including email sending and user interaction with confirmation links.
Why This Shape
The separation of registration and callback logic allows focused handling of user creation versus post-authentication actions. The register endpoint is optimized for input validation and environment-specific user provisioning, while the callback endpoint acts as a centralized handler for authentication completion.
Smart-linking is placed in GET /auth/callback because it depends on email verification being completed by Supabase. This ensures that the user.email is trusted before linking to existing clients records, maintaining data integrity. The design supports both immediate user linking and deferred identity resolution, enabling a smooth onboarding flow for users who interact with the system before creating an account.