Authentication Guide
Complete documentation for authentication in Layers, covering both user authentication (dashboard access) and API authentication (programmatic access).
Overview#
Layers uses two authentication systems:
| System | Purpose | Method |
|---|---|---|
| User Authentication | Access dashboard, manage keys, billing | Supabase Auth (Email/Password, Google OAuth) |
| API Authentication | Make API requests | API Keys (lyr_live_*, lyr_test_*) |
User Authentication (Dashboard)#
Sign Up Options#
Users can create a Layers account using:
- Email & Password - Traditional signup with email confirmation
- Google OAuth - One-click signup with Google account
Email & Password Flow#
- User enters email and password on [/signup](/signup)
- Supabase Auth creates the user account
- Confirmation email sent to user via Resend (transactional email service)
- User clicks confirmation link
- User redirected to dashboard
Email Delivery
Google OAuth Flow#
- User clicks "Continue with Google" on [/login](/login) or [/signup](/signup)
- Redirect to Google OAuth consent screen
- User authorizes Layers to access basic profile info
- Google redirects to `/auth/callback` with authorization code
- Server exchanges code for session tokens
- Session cookies set on response
- User redirected to dashboard
Authentication Architecture#
(Client)
(Server)
Auth
Key Components:
| Component | File | Purpose |
|---|---|---|
| Browser Client | [lib/supabase/browser.ts](lib/supabase/browser.ts) | Client-side Supabase for auth UI |
| Server Client | [lib/supabase/server.ts](lib/supabase/server.ts) | Server-side Supabase for protected routes |
| Middleware | [lib/supabase/middleware.ts](lib/supabase/middleware.ts) | Session refresh, route protection |
| OAuth Callback | [app/auth/callback/route.ts](app/auth/callback/route.ts) | Exchange OAuth code for session |
| Email Delivery | Resend (via Supabase) | Transactional emails (confirmations, password resets) |
Session Management#
Sessions are managed using HTTP-only cookies via @supabase/ssr:
- Cookie Name: sb-{project-ref}-auth-token
- Storage: HTTP-only, secure, SameSite=Lax
- Refresh: Automatic via middleware on each request
- Expiry: Configurable (default: 1 week, refreshable)
Protected Routes#
Routes under /dashboard/* require authentication:
// Middleware checks for valid session
const protectedPaths = ['/dashboard'];
if (isProtectedPath && !user) {
// Redirect to login with return URL
redirect('/login?redirectTo=/dashboard');
}Security Best Practices Implemented#
Server-Side Session Validation
Always use supabase.auth.getUser() on server, never trust client session. JWT validated against Supabase Auth server on each request.
HTTP-Only Cookies
Session tokens stored in HTTP-only cookies, not accessible via JavaScript (XSS protection).
PKCE Flow for OAuth
Code verifier stored securely during OAuth flow to prevent authorization code interception attacks.
Secure Cookie Attributes
Secure (HTTPS only in production), SameSite=Lax (CSRF protection), HttpOnly (no JavaScript access).
Automatic Session Refresh
Middleware refreshes tokens before expiry for seamless user experience without re-login.
API Authentication (Programmatic Access)#
API Key Format#
lyr_live_sk_1a2b3c4d5e6f7890...
lyr_test_sk_1a2b3c4d5e6f7890...| Prefix | Environment | Billing |
|---|---|---|
| lyr_live_ | Production | Deducts credits |
| lyr_test_ | Testing | Limited, no billing |
Using API Keys#
Include your API key in the Authorization header:
curl -X POST https://layers.hustletogether.com/api/v1/chat \
-H "Authorization: Bearer lyr_live_sk_xxxxx" \
-H "Content-Type: application/json" \
-d '{"model": "anthropic/claude-sonnet-4.5", "messages": [{"role": "user", "content": "Hello"}]}'API Key Security#
- Hashed Storage - Keys are hashed before storage (we can't see your full key)
- Server-Side Only - Never expose keys in client-side code
- Environment Variables - Store in .env, never commit to git
- Key Rotation - Generate new keys and revoke old ones if compromised
Rate Limiting#
Rate limits are applied per API key based on subscription tier:
| Tier | Requests/Minute |
|---|---|
| Free | 10 |
| Starter | 60 |
| Pro | 300 |
| Team | 1,000 |
Troubleshooting#
OAuth Login Not Working#
Symptoms: User authenticates with Google but gets redirected back to login.
Common Causes:
- Supabase Redirect URLs - Ensure https://yourdomain.com/auth/callback is in Supabase Auth settings
- Google OAuth Credentials - Verify Client ID and Secret are correct in Supabase
- Cookie Domain Mismatch - Ensure cookies are set for the correct domain
- Missing Environment Variables - Check NEXT_PUBLIC_SUPABASE_URL and NEXT_PUBLIC_SUPABASE_ANON_KEY
Debug Steps:
- Check browser Network tab for Set-Cookie headers on /auth/callback response
- Check server logs for [OAuth Callback] messages
- Verify Supabase dashboard shows the user was created
Session Not Persisting#
Symptoms: User logs in but appears logged out on page refresh.
Common Causes:
- Cookies not being set - Check Set-Cookie headers in response
- Middleware not running - Verify middleware.ts is configured correctly
- Cookie blocked - Third-party cookie settings in browser
API Key Authentication Errors#
| Error | Cause | Fix |
|---|---|---|
| Missing Authorization header | No header sent | Add Authorization: Bearer {key} |
| Invalid API key format | Wrong prefix | Use lyr_live_ or lyr_test_ |
| Invalid API key | Key not found | Check key is correct |
| API key is deactivated | Key disabled | Reactivate or create new key |
Configuration Checklist#
Supabase Dashboard Settings#
- Site URL: https://layers.hustletogether.com
- Redirect URLs: Include https://layers.hustletogether.com/auth/callback
- Google OAuth: Client ID and Secret configured
- Email Provider: Resend configured in Auth → Email settings
- Email Templates: Confirm signup template uses correct token hash format
Environment Variables#
# Supabase
NEXT_PUBLIC_SUPABASE_URL=https://xxx.supabase.co
NEXT_PUBLIC_SUPABASE_ANON_KEY=eyJ...
# Optional: Service role for admin operations
SUPABASE_SERVICE_ROLE_KEY=eyJ...
# Resend (configured in Supabase dashboard)
# No additional environment variables needed - configured via Supabase Auth settingsGoogle Cloud Console#
- OAuth 2.0 Client created
- Authorized redirect URIs: https://{project-ref}.supabase.co/auth/v1/callback
- Authorized JavaScript origins: Your app domain
Security Recommendations#
- Never log sensitive tokens - Access tokens, refresh tokens, API keys
- Use environment variables - Never hardcode credentials
- Implement rate limiting - Protect against brute force
- Monitor auth logs - Detect suspicious activity
- Rotate keys regularly - API keys and OAuth secrets
- Use HTTPS everywhere - Secure cookie transmission
- Validate on server - Never trust client-side auth state
Related Documentation
- Getting Started - Quick setup guide
- Billing & Credits - Understand billing
- Supabase Auth Docs ↗ - Official Supabase documentation