Authentication
Finnance uses phone-based authentication with OTP (One-Time Password) for secure, frictionless user login.
Overview
Finnance supports multiple authentication methods:
- OTP Link Authentication - Secure, time-limited links for quick login
- Phone + OTP - Traditional phone number verification
- Magic Links - Email-based passwordless authentication
- Session Management - Supabase-powered session handling
OTP Link Authentication
The OTP Link system provides frictionless authentication using secure, time-limited links that allow users to quickly log in with their phone number.
Features
- Secure Link Generation - Encrypted phone numbers and expiration times
- Automatic OTP Sending - Pre-filled phone numbers trigger automatic OTP delivery
- Flexible Redirects - Customizable redirect destinations after successful authentication
- Link Expiration - Configurable expiration times (default: 1 hour)
- Cross-Platform - Works on both web (Next.js) and mobile (Expo)
Generating OTP Links
import { OTPLinkService } from '@app-launch-kit/modules/auth/services/otpLinkService';
// Generate a secure OTP link
const link = OTPLinkService.generateOTPLink({
phone: '+1234567890',
redirectTo: '/accounts',
expiresIn: 3600, // 1 hour
});
console.log('Generated link:', link);
Link Formats
Secure Link (Recommended)
https://finnance.ai/otp-link?data=<encrypted_data>&hash=<security_hash>
Simple Link (Legacy)
https://finnance.ai/otp-link?phone=<phone_hash>&redirectTo=<path>
User Flow
- User receives link (via SMS, email, etc.)
- Clicks link → Redirected to
/otp-link - Phone number extracted → Pre-filled in form
- OTP automatically sent → User sees OTP input
- User enters OTP → Verification process
- Success → Redirected to specified page
API Endpoints
Generate OTP Link
POST
/api/otp-linkscurl -X POST https://api.finnance.ai/api/otp-links \
-H "Content-Type: application/json" \
-d '{
"phone": "+1234567890",
"redirectTo": "/accounts",
"expiresIn": 3600
}'
Response
{
"success": true,
"link": "https://finnance.ai/otp-link?data=...&hash=...",
"expiresIn": 3600,
"phone": "+1234567890",
"redirectTo": "/accounts"
}
Generate via GET
curl "https://api.finnance.ai/api/otp-links?phone=+1234567890&redirectTo=/accounts"
Security Features
Encrypted Data
Phone numbers are encrypted in secure links using AES encryption:
// Link data is encrypted
const encryptedData = encrypt({
phone: '+1234567890',
expires: Date.now() + expiresIn * 1000,
redirectTo: '/accounts'
});
Hash Validation
Links include security hashes to prevent tampering:
const hash = createHash('sha256')
.update(encryptedData + secret)
.digest('hex');
Time Expiration
Links expire after configurable time (default: 1 hour):
const isExpired = decoded.expires < Date.now();
if (isExpired) {
throw new Error('Link has expired');
}
Configuration
Environment Variables
# Required for OTP link encryption
NEXT_PUBLIC_OTP_SECRET=your-custom-secret-key
# Supabase Auth
NEXT_PUBLIC_SUPABASE_URL=https://your-project.supabase.co
NEXT_PUBLIC_SUPABASE_ANON_KEY=your-anon-key
Route Configuration
// In config/index.ts
routes: {
otpLink: { path: '/otp-link', title: 'Quick Login' },
login: { path: '/login', title: 'Login' },
signup: { path: '/signup', title: 'Sign Up' },
}
Integration Examples
Email Integration
// Send OTP link via email
const link = OTPLinkService.generateOTPLink({
phone: user.phone,
redirectTo: '/accounts',
});
await emailService.send({
to: user.email,
subject: 'Login to Finnance',
body: `Click here to login: ${link}`
});
SMS Integration
// Send OTP link via SMS
const link = OTPLinkService.generateOTPLink({
phone: user.phone,
redirectTo: '/accounts',
});
await smsService.send({
to: user.phone,
message: `Login to Finnance: ${link}`
});
Session Management
Finnance uses Supabase Auth for session management:
import { createClient } from '@supabase/supabase-js';
const supabase = createClient(
process.env.NEXT_PUBLIC_SUPABASE_URL!,
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!
);
// Get current session
const { data: { session } } = await supabase.auth.getSession();
// Listen for auth changes
supabase.auth.onAuthStateChange((event, session) => {
if (event === 'SIGNED_IN') {
console.log('User signed in:', session?.user);
}
});
Testing
Use the OTPLinkTester utility for testing:
import { OTPLinkTester } from '@app-launch-kit/modules/auth/utils/testOTPLink';
// Test complete flow
const result = OTPLinkTester.testCompleteFlow('+1234567890', '/accounts');
console.log(result);
// Generate test link
const link = OTPLinkTester.generateTestLink('+1234567890', '/accounts');
// Validate link
const validation = OTPLinkTester.validateTestLink(link);
Best Practices
- Link Security - Keep generated links private and secure
- Expiration - Use appropriate expiration times based on use case
- Rate Limiting - Implement rate limiting for link generation
- Monitoring - Track link usage and success rates
- Cleanup - Regularly clean up expired links from database
- Phone Format - Always use international format (+1234567890)
Troubleshooting
Common Issues
| Issue | Solution |
|---|---|
| Link Expired | Check expiration time and regenerate |
| Invalid Hash | Ensure OTP_SECRET environment variable is set |
| Phone Format | Use international format (+1234567890) |
| Redirect Issues | Verify redirect paths exist in your app |
Debug Mode
// Enable debug logging
const link = OTPLinkService.generateOTPLink({
phone: '+1234567890',
redirectTo: '/accounts',
});
console.log('Debug link data:', OTPLinkService.extractOTPLinkData(link));
Next Steps
- Setup Guide - Configure your development environment
- Agent Architecture - Learn about the AI system
- Webhooks - Handle authentication events