Learn how to integrate your authentication system with Pika Framework, replacing the default mock authentication with your production authentication provider (OAuth, SAML, JWT, or custom).
What You'll Accomplish
Section titled “What You'll Accomplish”By the end of this guide, you will:
- Create a custom authentication provider for your auth system
- Implement user authentication and token validation
- Configure user types and roles for access control
- Deploy your custom authentication to production
Prerequisites
Section titled “Prerequisites”Before starting, ensure you have:
- A running Pika installation (local or deployed)
- Access to your authentication provider (OAuth, SAML, JWT, etc.)
- Authentication provider credentials (client ID, secret, etc.)
- Basic understanding of TypeScript and async/await patterns
Understanding the Data Model
Section titled “Understanding the Data Model”Pika uses a two-tier data structure for user information:
AuthenticatedUser<T, U>
Section titled “AuthenticatedUser<T, U>”T (Auth Data):
- Sensitive authentication tokens and session data
- Stored in encrypted cookies only (never database)
- Available server-side only
- Not accessible to agents or tools
- Must be
Record<string, string>or undefined
U (Custom Data):
- Business-specific user information
- Stored in encrypted cookies AND database
- Available to agent tools (but NOT the agent itself)
- Persists across sessions
- Must be
Record<string, string>or undefined
Step 1: Define Your Data Types
Section titled “Step 1: Define Your Data Types”Create type definitions for your authentication and custom user data.
Location: apps/pika-chat/src/lib/server/auth-provider/types.ts
// Auth data - stored securely in cookies, never saved to databaseexport interface YourCustomAuthData { accessToken: string; refreshToken?: string; expiresAt?: number; // Add your auth-specific properties here}
// Custom data - saved to database with user recordexport interface YourCustomUserData { email?: string; companyId?: string; companyName?: string; accountId?: string; // Add your custom user properties here}Step 2: Create Your Auth Provider
Section titled “Step 2: Create Your Auth Provider”Implement your authentication provider by extending the AuthProvider<T, U> class.
Location: apps/pika-chat/src/lib/server/auth-provider/index.ts
import type { RequestEvent } from '@sveltejs/kit';import type { AuthenticatedUser, AuthenticateResult } from 'pika-shared/types/chatbot/chatbot-types';import { AuthProvider, NotAuthenticatedError, ForceUserToReauthenticateError } from '../auth/types';import { redirect } from '@sveltejs/kit';import type { YourCustomAuthData, YourCustomUserData } from './types';
export default class YourAuthProvider extends AuthProvider<YourCustomAuthData, YourCustomUserData> { async authenticate(event: RequestEvent): Promise<AuthenticateResult<YourCustomAuthData, YourCustomUserData>> { // Check if this is a login route if (event.url.pathname.startsWith('/auth/login')) { return this.startOAuthFlow(event); }
// Extract auth token from cookies or headers const authToken = this.extractAuthToken(event); if (!authToken) { // No token found - redirect to login return { redirectTo: redirect(302, '/login') }; }
try { // Validate token and get user data const userData = await this.getUserFromAuthProvider(authToken); const user = this.createAuthenticatedUser(userData, authToken); return { authenticatedUser: user }; } catch (error) { // Token invalid or expired throw new NotAuthenticatedError('Invalid or expired token'); } }
async validateUser( event: RequestEvent, user: AuthenticatedUser<YourCustomAuthData, YourCustomUserData> ): Promise<AuthenticatedUser<YourCustomAuthData, YourCustomUserData> | undefined> { // Check if the user's access token is still valid const accessToken = user.authData.accessToken;
try { const isValid = await this.validateTokenWithProvider(accessToken);
if (isValid) { return undefined; // Token is still valid }
// Token expired - try to refresh if (user.authData.refreshToken) { try { const newTokens = await this.refreshTokens(user.authData.refreshToken); const updatedUser = { ...user }; updatedUser.authData = { ...updatedUser.authData, accessToken: newTokens.access_token, refreshToken: newTokens.refresh_token, expiresAt: newTokens.expires_at }; return updatedUser; } catch (refreshError) { throw new ForceUserToReauthenticateError('Token refresh failed'); } }
throw new ForceUserToReauthenticateError('Token expired'); } catch (error) { if (error instanceof ForceUserToReauthenticateError) { throw error; } throw new ForceUserToReauthenticateError('Token validation failed'); } }
private extractAuthToken(event: RequestEvent): string | null { return event.cookies.get('your-auth-token') || event.request.headers.get('authorization')?.replace('Bearer ', ''); }
private async getUserFromAuthProvider(token: string): Promise<any> { const response = await fetch('https://your-auth-provider.com/api/user', { headers: { Authorization: `Bearer ${token}` } });
if (!response.ok) { throw new Error('Failed to get user data'); }
return response.json(); }
private createAuthenticatedUser( userData: any, token: string ): AuthenticatedUser<YourCustomAuthData, YourCustomUserData> { return { userId: userData.id, firstName: userData.firstName, lastName: userData.lastName, // User type for access control userType: userData.isEmployee ? 'internal-user' : 'external-user', // Roles for permissions roles: userData.roles || [], // Custom data - saved to database customData: { email: userData.email, companyId: userData.companyId, companyName: userData.companyName, accountId: userData.accountId }, // Auth data - secure cookie only authData: { accessToken: token, refreshToken: userData.refreshToken, expiresAt: userData.expiresAt }, features: { instruction: { type: 'instruction', instruction: 'You are a helpful assistant.' }, history: { type: 'history', history: true } } }; }}Step 3: Configure User Types and Roles
Section titled “Step 3: Configure User Types and Roles”Implement logic to assign user types and roles based on your authentication provider's data.
// Determine user type based on email domainfunction determineUserType(email: string): 'internal-user' | 'external-user' { const companyDomains = ['yourcompany.com', 'corp.yourcompany.com']; const emailDomain = email.split('@')[1];
return companyDomains.includes(emailDomain) ? 'internal-user' : 'external-user';}
// Extract roles from your auth providerfunction extractUserRoles(userData: any): string[] { const roles: string[] = [];
// Add Pika admin role for super admins if (userData.isSuperAdmin) { roles.push('pika:content-admin'); }
// Add custom business roles if (userData.permissions?.includes('manage_team')) { roles.push('team-manager'); }
return roles;}Step 4: Test Your Authentication
Section titled “Step 4: Test Your Authentication”Local Testing
Section titled “Local Testing”- Start your local development server:
cd apps/pika-chatpnpm run dev- Navigate to your application in a browser
- Verify the authentication flow:
- Redirects to login when not authenticated
- Successfully authenticates with valid credentials
- Stores user data correctly
- Maintains session across page refreshes
Production Deployment
Section titled “Production Deployment”Before deploying to production:
Testing Checklist
Section titled “Testing Checklist”Verify your authentication implementation:
Troubleshooting
Section titled “Troubleshooting”Common Issues
Section titled “Common Issues”"Type errors with generics"
- Ensure you use
extends AuthProvider<YourAuthData, YourCustomData>notimplements - Don't redeclare generic parameters on your class
"Redirect loops"
- Check that
/loginand/auth/*routes don't trigger authentication - Verify your
extractAuthTokenlogic is correct
"Cookie issues"
- Verify cookie domain configuration matches your deployment
- Ensure
SameSiteandSecureflags are set correctly - Check cookie size limits if storing large auth data
"Token validation fails"
- Enable debug logging with
DEBUG_AUTH=true - Verify token format matches your auth provider
- Check token expiration handling
Next Steps
Section titled “Next Steps”Now that you have custom authentication:
- Configure Chat App Access Control - Control which users can access which chat apps
- Set Up User-to-Organization Mapping - Map users to organizations for multi-tenancy
- Work with Entities - Configure entity-based access control
Related Documentation
Section titled “Related Documentation”- Authentication Concepts - Understanding Pika's security model
- User Types and Roles Reference - Complete user type reference
- Access Control Guide - Detailed access control rules