Layers
Security

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:

SystemPurposeMethod
User AuthenticationAccess dashboard, manage keys, billingSupabase Auth (Email/Password, Google OAuth)
API AuthenticationMake API requestsAPI Keys (lyr_live_*, lyr_test_*)

User Authentication (Dashboard)#

Sign Up Options#

Users can create a Layers account using:

  1. Email & Password - Traditional signup with email confirmation
  2. Google OAuth - One-click signup with Google account

Email & Password Flow#

  1. User enters email and password on [/signup](/signup)
  2. Supabase Auth creates the user account
  3. Confirmation email sent to user via Resend (transactional email service)
  4. User clicks confirmation link
  5. User redirected to dashboard

Email Delivery

Layers uses Resend for all transactional emails including signup confirmations, password resets, and magic links. Resend is integrated with Supabase Auth for reliable email delivery.

Google OAuth Flow#

  1. User clicks "Continue with Google" on [/login](/login) or [/signup](/signup)
  2. Redirect to Google OAuth consent screen
  3. User authorizes Layers to access basic profile info
  4. Google redirects to `/auth/callback` with authorization code
  5. Server exchanges code for session tokens
  6. Session cookies set on response
  7. User redirected to dashboard

Authentication Architecture#

Browser
(Client)
Next.js App
(Server)
Supabase
Auth
Cookies ← → JWT Tokens

Key Components:

ComponentFilePurpose
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 DeliveryResend (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...
PrefixEnvironmentBilling
lyr_live_ProductionDeducts credits
lyr_test_TestingLimited, 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#

  1. Hashed Storage - Keys are hashed before storage (we can't see your full key)
  2. Server-Side Only - Never expose keys in client-side code
  3. Environment Variables - Store in .env, never commit to git
  4. Key Rotation - Generate new keys and revoke old ones if compromised

Rate Limiting#

Rate limits are applied per API key based on subscription tier:

TierRequests/Minute
Free10
Starter60
Pro300
Team1,000

Troubleshooting#

OAuth Login Not Working#

Symptoms: User authenticates with Google but gets redirected back to login.

Common Causes:

  1. Supabase Redirect URLs - Ensure https://yourdomain.com/auth/callback is in Supabase Auth settings
  2. Google OAuth Credentials - Verify Client ID and Secret are correct in Supabase
  3. Cookie Domain Mismatch - Ensure cookies are set for the correct domain
  4. Missing Environment Variables - Check NEXT_PUBLIC_SUPABASE_URL and NEXT_PUBLIC_SUPABASE_ANON_KEY

Debug Steps:

  1. Check browser Network tab for Set-Cookie headers on /auth/callback response
  2. Check server logs for [OAuth Callback] messages
  3. Verify Supabase dashboard shows the user was created

Session Not Persisting#

Symptoms: User logs in but appears logged out on page refresh.

Common Causes:

  1. Cookies not being set - Check Set-Cookie headers in response
  2. Middleware not running - Verify middleware.ts is configured correctly
  3. Cookie blocked - Third-party cookie settings in browser

API Key Authentication Errors#

ErrorCauseFix
Missing Authorization headerNo header sentAdd Authorization: Bearer {key}
Invalid API key formatWrong prefixUse lyr_live_ or lyr_test_
Invalid API keyKey not foundCheck key is correct
API key is deactivatedKey disabledReactivate 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 settings

Google 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#

  1. Never log sensitive tokens - Access tokens, refresh tokens, API keys
  2. Use environment variables - Never hardcode credentials
  3. Implement rate limiting - Protect against brute force
  4. Monitor auth logs - Detect suspicious activity
  5. Rotate keys regularly - API keys and OAuth secrets
  6. Use HTTPS everywhere - Secure cookie transmission
  7. Validate on server - Never trust client-side auth state

Related Documentation