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

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

  1. User receives link (via SMS, email, etc.)
  2. Clicks link → Redirected to /otp-link
  3. Phone number extracted → Pre-filled in form
  4. OTP automatically sent → User sees OTP input
  5. User enters OTP → Verification process
  6. Success → Redirected to specified page

API Endpoints

Generate OTP Link

POST
/api/otp-links
curl -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

  1. Link Security - Keep generated links private and secure
  2. Expiration - Use appropriate expiration times based on use case
  3. Rate Limiting - Implement rate limiting for link generation
  4. Monitoring - Track link usage and success rates
  5. Cleanup - Regularly clean up expired links from database
  6. Phone Format - Always use international format (+1234567890)

Troubleshooting

Common Issues

IssueSolution
Link ExpiredCheck expiration time and regenerate
Invalid HashEnsure OTP_SECRET environment variable is set
Phone FormatUse international format (+1234567890)
Redirect IssuesVerify 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

Was this page helpful?