Overview
Stytch provides the following capabilities in Definable:- User Authentication: Password-based and magic link authentication
- Session Management: JWT-based session tokens validated via JWKS
- User Invitations: Email-based invitation system for organization onboarding
- Webhook Events: Real-time user lifecycle event processing
- External User Tracking: Links Stytch user IDs to internal user records
Architecture
JWKS-Based JWT Validation
Definable uses Stytch’s JWKS (JSON Web Key Set) endpoint to validate session tokens locally without making API calls to Stytch for every request.How JWKS Validation Works
- Client receives JWT from Stytch after successful login
- Client sends JWT in
Authorization: Bearer <token>header - JWTBearer middleware extracts the token
- JWKS client fetches public keys from Stytch’s JWKS endpoint (cached)
- Token is cryptographically verified using the public key
- User lookup using the
subclaim (stytch_id) from decoded token - User context returned to the request handler
Implementation
The JWKS verification is implemented insrc/libs/stytch/v1/jkws.py:
JWTBearer Dependency
TheJWTBearer class in src/dependencies/security.py uses Stytch JWKS validation:
Key Features
- RS256 Algorithm: Stytch uses asymmetric encryption (public/private key pairs)
- Cached Keys: Public keys are cached for 10 minutes to reduce latency
- Audience Validation: Ensures token was issued for your Stytch project
- Claims Verification: Validates expiration, issued-at, audience, subject, and issuer
- WebSocket Support: Same validation works for WebSocket connections using query parameters
Webhook Integration with Svix
Stytch sends webhook events to Definable when user lifecycle events occur (user creation, deletion, etc.). These webhooks are secured using Svix signature verification.Webhook Flow
- User event occurs in Stytch (e.g., user signs up)
- Stytch sends webhook to Definable’s
/api/authendpoint - Svix headers included:
svix-id,svix-timestamp,svix-signature - Signature verified using webhook secret
- Event processed based on action type
Svix Signature Verification
Implemented insrc/utils/verify_wh.py:
Webhook Handler
The webhook handler insrc/services/auth/service.py processes user events:
User Registration Flows
Definable supports two user registration flows via Stytch:1. Regular User Registration
Flow:- User signs up via Stytch (password or magic link)
- Stytch webhook triggers with
action: "CREATE" - UserModel created with
stytch_idfrom webhook - Default organization created and user assigned “owner” role
- Default auth token generated (365-day JWT)
- Starter subscription with initial credits created
2. Invitation-Based Registration
Flow:- Admin invites user via email
- Pre-created UserModel with
stytch_id=None, status=“invited” - Invitation email sent via Stytch with
trusted_metadata.external_user_id - User clicks invitation link and signs up via Stytch
- Stytch webhook triggers with
type: "invitation"in untrusted_metadata - UserModel updated with
stytch_idfrom Stytch - OrganizationMember status changed from “invited” to “active”
- Invitation status updated to “ACCEPTED”
Sending Invitations
When an admin invites a user, Stytch is used to send the invitation email:Password Authentication
Definable supports password-based authentication via Stytch:Sign Up with Password
Login with Password
UserModel and stytch_id
TheUserModel stores the Stytch user ID to link internal users with Stytch:
stytch_idis nullable to support invited users who haven’t signed up yetstytch_idis unique and indexed for fast lookups during authenticationpasswordfield is deprecated - passwords are managed by Stytch- When invitation is accepted,
stytch_idis populated from webhook
Configuration
Stytch integration requires the following environment variables:Environment Settings
Defined inconfig/settings.py:
JWKS Endpoints
- Test Environment:
https://test.stytch.com/v1/sessions/jwks/{project_id} - Live Environment:
https://api.stytch.com/v1/sessions/jwks/{project_id}
Security Considerations
Token Validation
- Algorithm: RS256 (asymmetric cryptography)
- Signature Verification: Tokens verified using Stytch’s public keys
- Claim Validation: exp, iat, aud, sub, iss claims are required
- Expiration: Tokens expire based on Stytch session duration (default: 1440 minutes / 24 hours)
Webhook Security
- Svix Signatures: All webhooks must have valid Svix signatures
- HMAC-SHA256: Signatures use HMAC with SHA256 hashing
- Timestamp Verification: Prevents replay attacks
- Secret Management: Webhook secret stored securely in environment variables
Metadata Security
- Trusted Metadata: Stored securely by Stytch, not editable by users
- Used for:
external_user_id,is_invitedflag
- Used for:
- Untrusted Metadata: Can be set by clients
- Used for:
type: "invitation",temp: truefor test users - Never trust for security decisions
- Used for:
Testing
Test Endpoints
Definable provides test endpoints for local development:POST /api/auth/test_signup- Create user with passwordPOST /api/auth/test_login- Authenticate with passwordPOST /api/auth/verify_api_key- Verify API key validity
untrusted_metadata: {"temp": true} to prevent webhook processing during development.
Example Test Flow
Implementation Files
Core Files
src/dependencies/security.py: JWTBearer class with JWKS validationsrc/libs/stytch/v1/jkws.py: JWKS client and token verificationsrc/libs/stytch/v1/base.py: Stytch API wrappersrc/services/auth/service.py: Webhook handler and user creationsrc/utils/verify_wh.py: Svix signature verificationsrc/models/auth_model.py: UserModel with stytch_id field
Configuration Files
config/settings.py: Stytch environment variables.env: Stytch credentials and configuration
Troubleshooting
Invalid Token Errors
Symptoms:- Error: “Invalid token signature”
- Error: “Token has expired”
- Verify token is from correct Stytch environment (test vs live)
- Check JWKS endpoint is accessible
- Ensure
STYTCH_PROJECT_IDmatches the token’s audience claim - Verify token hasn’t expired (check
expclaim)
Webhook Signature Failures
Symptoms:- Error: “Invalid signature” (400 status)
- Webhooks not processing
- Verify
STYTCH_WEBHOOK_SECRETis correct - Check webhook secret format (should start with
whsec_) - Ensure webhook body is not modified before verification
- Verify headers
svix-id,svix-timestamp,svix-signatureare present
User Not Found After Login
Symptoms:- Login succeeds in Stytch
- Error: “User not found” in Definable
- Check if webhook was processed successfully
- Verify
stytch_idmatches between Stytch and UserModel - Check if user was created with
temp: trueflag (skips webhook processing) - Manually create user if webhook failed
Next Steps
- JWT Authentication: General JWT implementation details
- Invitation Flow: Complete invitation process documentation
- Authentication Overview: Complete authentication system overview
- Troubleshooting: Common authentication issues