Authentication
Integrate Authentication
This guide provides practical implementation patterns for integrating CashIn's Authentication endpoints. These endpoints handle user signup, signin, verification, and session management while maintaining seamless user experiences and proper instance tracking.
Authentication Endpoints
|
Endpoint |
Method |
Purpose |
Key Parameters |
Response Data |
|---|---|---|---|---|
|
|
POST |
Register new user with tracking |
|
|
|
|
POST |
Initiate signin process |
|
|
|
|
POST |
Complete signin with verification |
|
|
|
|
POST |
Resend verification codes |
|
|
|
|
POST |
Sign out user and invalidate session |
|
Success confirmation |
|
|
POST |
Check auto-authentication eligibility |
|
|
Authentication Setup
All Authentication endpoints require Bearer token authentication using your partner secret key.
const headers = {
'Authorization': 'Bearer sk_live_abc123def456...',
'Content-Type': 'application/json',
'X-Request-ID': generateUniqueId() // Recommended for debugging
};
Integration Patterns
Pattern 1: User Signup Flow
Handle new user registration with automatic instance migration and campaign attribution.
async function handleUserSignup(userData, instanceContext = {}) {
const signupData = {
email: userData.email,
name: userData.name,
handle: userData.handle || generateHandle(userData.name),
social_media_handles: userData.socialHandles || {},
campaignId: instanceContext.campaignId,
fingerprint_id: instanceContext.fingerprintId,
referrer_id: instanceContext.referrerId,
existing_instance_id: localStorage.getItem('cashin_instance_id')
};
try {
const response = await fetch('/partner/v1/auth/signup', {
method: 'POST',
headers,
body: JSON.stringify(signupData)
});
const result = await response.json();
if (result.success) {
// Store new user data and instance information
const { user, instance_id, instance_migrated } = result.data;
// Update stored instance if migration occurred
if (instance_migrated) {
localStorage.setItem('cashin_instance_id', instance_id);
console.log('Instance successfully migrated to authenticated user');
}
// Store user session data
localStorage.setItem('cashin_user', JSON.stringify(user));
localStorage.setItem('cashin_auth_token', user.id);
return {
success: true,
user,
instanceMigrated: instance_migrated
};
} else {
return { success: false, error: result.message };
}
} catch (error) {
console.error('Signup failed:', error);
return { success: false, error: 'Network error during signup' };
}
}
// Usage example
async function onSignupFormSubmit(formData) {
const instanceContext = {
campaignId: getUrlParameter('campaign_id'),
fingerprintId: await generateFingerprint(),
referrerId: getUrlParameter('ref')
};
const result = await handleUserSignup(formData, instanceContext);
if (result.success) {
showSuccessMessage('Account created successfully!');
redirectToUserDashboard();
} else {
showErrorMessage(result.error);
}
}
Pattern 2: Multi-Step Signin Flow
Implement the complete signin process with identifier validation and code verification.
class SigninFlowManager {
constructor() {
this.instanceId = localStorage.getItem('cashin_instance_id');
this.signinState = {};
}
async initiateSignin(identifier, identifierType = 'email') {
try {
const response = await fetch('/partner/v1/auth/signin', {
method: 'POST',
headers,
body: JSON.stringify({
identifier,
identifier_type: identifierType,
instance_id: this.instanceId
})
});
const result = await response.json();
if (result.success) {
this.signinState = {
userFound: result.data.user_found,
partnerRelationship: result.data.partner_relationship,
verificationMethods: result.data.verification_methods,
user: result.data.user
};
return {
success: true,
userFound: result.data.user_found,
verificationSent: result.data.verification_sent,
methods: result.data.verification_methods
};
}
return { success: false, error: result.message };
} catch (error) {
console.error('Signin initiation failed:', error);
return { success: false, error: 'Network error' };
}
}
async verifySignin(verificationType, verificationData) {
const requestBody = {
instance_id: this.instanceId,
verification_type: verificationType,
...verificationData
};
try {
const response = await fetch('/partner/v1/auth/signin/verify', {
method: 'POST',
headers,
body: JSON.stringify(requestBody)
});
const result = await response.json();
if (result.success && result.data.verified) {
// Store authenticated user data
const { user, authToken, insider, identifiers, partnerRules } = result.data;
localStorage.setItem('cashin_user', JSON.stringify(user));
localStorage.setItem('cashin_auth_token', authToken);
localStorage.setItem('cashin_insider_data', JSON.stringify(insider));
localStorage.setItem('cashin_partner_rules', JSON.stringify(partnerRules));
return {
success: true,
user,
insider,
partnerRules,
instanceUpgraded: result.data.instance_upgraded
};
}
return { success: false, error: result.message };
} catch (error) {
console.error('Signin verification failed:', error);
return { success: false, error: 'Verification failed' };
}
}
async resendVerificationCode(methods = ['email']) {
try {
const response = await fetch('/partner/v1/auth/signin/resend', {
method: 'POST',
headers,
body: JSON.stringify({
instance_id: this.instanceId,
methods
})
});
const result = await response.json();
return {
success: result.success,
sentMethods: result.data?.sent_methods || []
};
} catch (error) {
console.error('Resend failed:', error);
return { success: false, error: 'Failed to resend codes' };
}
}
}
// Implementation example
async function handleSigninProcess() {
const signinManager = new SigninFlowManager();
const email = document.getElementById('email').value;
// Step 1: Initiate signin
const initResult = await signinManager.initiateSignin(email, 'email');
if (!initResult.success) {
showError(initResult.error);
return;
}
if (!initResult.userFound) {
// Redirect to signup flow
redirectToSignup({ email });
return;
}
// Step 2: Show verification UI
showVerificationForm(initResult.methods);
// Step 3: Handle verification
document.getElementById('verify-btn').onclick = async () => {
const code = document.getElementById('verification-code').value;
const verifyResult = await signinManager.verifySignin('code', {
verification_code: code,
verification_method: 'email'
});
if (verifyResult.success) {
showSuccess('Signed in successfully!');
applyPartnerRules(verifyResult.partnerRules);
redirectToUserDashboard();
} else {
showError(verifyResult.error);
}
};
}
Pattern 3: Authentication Context Detection
Implement smart authentication based on device fingerprints and URL context.
class AuthContextManager {
async checkAuthenticationContext(url, integrationType = 'web_link') {
const fingerprint = await this.generateDetailedFingerprint();
try {
const response = await fetch('/partner/v1/auth/context', {
method: 'POST',
headers,
body: JSON.stringify({
url,
integration_type: integrationType,
fingerprint
})
});
const result = await response.json();
if (result.success) {
const {
instance_id,
is_authenticated,
match_strength,
discount_id,
referrer_id
} = result.data;
return {
shouldAutoAuth: is_authenticated && match_strength === 'high',
instanceId: instance_id,
discountId: discount_id,
referrerId: referrer_id,
matchStrength: match_strength
};
}
return { shouldAutoAuth: false };
} catch (error) {
console.error('Auth context check failed:', error);
return { shouldAutoAuth: false };
}
}
async generateDetailedFingerprint() {
return {
id: await this.generateFingerprintId(),
userAgent: navigator.userAgent,
screen: {
width: screen.width,
height: screen.height,
colorDepth: screen.colorDepth
},
timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,
language: navigator.language,
platform: navigator.platform,
cookieEnabled: navigator.cookieEnabled,
doNotTrack: navigator.doNotTrack
};
}
async generateFingerprintId() {
const components = [
navigator.userAgent,
navigator.language,
screen.width + 'x' + screen.height,
new Date().getTimezoneOffset(),
navigator.platform
];
const fingerprint = components.join('|');
const encoder = new TextEncoder();
const data = encoder.encode(fingerprint);
const hashBuffer = await crypto.subtle.digest('SHA-256', data);
const hashArray = Array.from(new Uint8Array(hashBuffer));
return hashArray.map(b => b.toString(16).padStart(2, '0')).join('');
}
}
// Usage on page load
async function initializeAuthentication() {
const authContext = new AuthContextManager();
const currentUrl = window.location.href;
const context = await authContext.checkAuthenticationContext(currentUrl);
if (context.shouldAutoAuth) {
// User should be automatically authenticated
localStorage.setItem('cashin_instance_id', context.instanceId);
if (context.discountId) {
applyDiscount(context.discountId);
}
showAutoAuthSuccess();
} else {
// Show normal signin/signup options
showAuthenticationOptions();
}
}
Pattern 4: Session Management and Signout
Handle user signout and session cleanup properly.
async function handleUserSignout() {
const instanceId = localStorage.getItem('cashin_instance_id');
if (!instanceId) {
// No active session to sign out
clearLocalAuthData();
return { success: true };
}
try {
const response = await fetch('/partner/v1/auth/signout', {
method: 'POST',
headers,
body: JSON.stringify({
instance_id: instanceId
})
});
const result = await response.json();
if (result.success) {
console.log('User signed out successfully');
} else {
console.warn('Signout API failed, but cleaning local data:', result.message);
}
} catch (error) {
console.error('Signout request failed:', error);
} finally {
// Always clean up local storage regardless of API response
clearLocalAuthData();
}
return { success: true };
}
function clearLocalAuthData() {
const keysToRemove = [
'cashin_instance_id',
'cashin_user',
'cashin_auth_token',
'cashin_insider_data',
'cashin_partner_rules',
'cashin_expires_at'
];
keysToRemove.forEach(key => localStorage.removeItem(key));
}
// Auto-signout on page unload
window.addEventListener('beforeunload', handleUserSignout);
// Manual signout button handler
document.getElementById('signout-btn')?.addEventListener('click', async () => {
await handleUserSignout();
showMessage('Signed out successfully');
redirectToHomePage();
});
Complete Authentication Integration
Unified Authentication Manager
class CashInAuthManager {
constructor(apiKey) {
this.apiKey = apiKey;
this.headers = {
'Authorization': `Bearer ${apiKey}`,
'Content-Type': 'application/json'
};
this.contextManager = new AuthContextManager();
this.signinManager = new SigninFlowManager();
}
async initialize() {
// Check for existing authentication context
const context = await this.contextManager.checkAuthenticationContext(
window.location.href
);
if (context.shouldAutoAuth) {
return this.handleAutoAuthentication(context);
}
// Check for existing local session
const existingUser = this.getCurrentUser();
if (existingUser) {
return this.validateExistingSession();
}
return { authenticated: false, method: 'none' };
}
async handleAutoAuthentication(context) {
localStorage.setItem('cashin_instance_id', context.instanceId);
if (context.discountId) {
this.applyDiscount(context.discountId);
}
return {
authenticated: true,
method: 'auto',
instanceId: context.instanceId,
matchStrength: context.matchStrength
};
}
async validateExistingSession() {
const instanceId = localStorage.getItem('cashin_instance_id');
if (!instanceId) {
this.clearAuthData();
return { authenticated: false, method: 'expired' };
}
// Validate instance is still active (using instance validation endpoint)
try {
const response = await fetch('/partner/v1/instance/validate', {
method: 'POST',
headers: this.headers,
body: JSON.stringify({ instance_id: instanceId })
});
const result = await response.json();
if (result.success && result.data.valid) {
return {
authenticated: true,
method: 'existing',
instance: result.data.instance
};
} else {
this.clearAuthData();
return { authenticated: false, method: 'expired' };
}
} catch (error) {
console.error('Session validation failed:', error);
return { authenticated: false, method: 'error' };
}
}
getCurrentUser() {
const userStr = localStorage.getItem('cashin_user');
return userStr ? JSON.parse(userStr) : null;
}
getInsiderData() {
const insiderStr = localStorage.getItem('cashin_insider_data');
return insiderStr ? JSON.parse(insiderStr) : null;
}
getPartnerRules() {
const rulesStr = localStorage.getItem('cashin_partner_rules');
return rulesStr ? JSON.parse(rulesStr) : [];
}
applyDiscount(discountId) {
// Implement your discount application logic
console.log('Applying discount:', discountId);
// Example: Add discount indicator to UI
const discountBanner = document.createElement('div');
discountBanner.className = 'cashin-discount-banner';
discountBanner.textContent = 'Special CashIn discount applied!';
document.body.prepend(discountBanner);
}
clearAuthData() {
const keysToRemove = [
'cashin_instance_id',
'cashin_user',
'cashin_auth_token',
'cashin_insider_data',
'cashin_partner_rules',
'cashin_expires_at'
];
keysToRemove.forEach(key => localStorage.removeItem(key));
}
async signout() {
const instanceId = localStorage.getItem('cashin_instance_id');
if (instanceId) {
try {
await fetch('/partner/v1/auth/signout', {
method: 'POST',
headers: this.headers,
body: JSON.stringify({ instance_id: instanceId })
});
} catch (error) {
console.error('Signout API call failed:', error);
}
}
this.clearAuthData();
return { success: true };
}
}
Page Load Integration
// Initialize authentication on every page load
document.addEventListener('DOMContentLoaded', async () => {
const authManager = new CashInAuthManager('sk_live_your_api_key');
try {
const authResult = await authManager.initialize();
switch (authResult.method) {
case 'auto':
showAutoAuthMessage();
setupAuthenticatedUI(authResult);
break;
case 'existing':
console.log('Existing session restored');
setupAuthenticatedUI(authResult);
break;
case 'expired':
case 'none':
default:
setupUnauthenticatedUI();
break;
}
} catch (error) {
console.error('Authentication initialization failed:', error);
setupUnauthenticatedUI();
}
});
function setupAuthenticatedUI(authResult) {
const authManager = new CashInAuthManager('sk_live_your_api_key');
const user = authManager.getCurrentUser();
const insider = authManager.getInsiderData();
const rules = authManager.getPartnerRules();
// Show user-specific content
document.getElementById('user-name').textContent = user?.name || 'User';
// Apply partner rules (discounts, special offers, etc.)
rules.forEach(rule => {
if (rule.isActive) {
applyPartnerRule(rule);
}
});
// Show insider-specific features
if (insider?.verifiedStatus === 'verified') {
showVerifiedInsiderBenefits();
}
// Setup signout functionality
document.getElementById('signout-btn').onclick = async () => {
await authManager.signout();
location.reload();
};
}
function setupUnauthenticatedUI() {
// Show signin/signup options
document.getElementById('auth-buttons').style.display = 'block';
// Setup signin flow
document.getElementById('signin-btn').onclick = () => {
showSigninModal();
};
// Setup signup flow
document.getElementById('signup-btn').onclick = () => {
showSignupModal();
};
}
Error Handling and Edge Cases
Comprehensive Error Handler
class AuthErrorHandler {
static handleAuthError(error, context = {}) {
console.error('Authentication error:', error, context);
switch (error.type) {
case 'network':
return {
userMessage: 'Connection error. Please check your internet and try again.',
retry: true
};
case 'validation':
return {
userMessage: error.fields?.map(f => f.message).join(', ') || 'Invalid input',
retry: false
};
case 'conflict':
return {
userMessage: 'Account already exists. Try signing in instead.',
retry: false,
redirect: 'signin'
};
case 'rate_limit':
return {
userMessage: 'Too many attempts. Please wait a moment and try again.',
retry: true,
delay: 30000
};
default:
return {
userMessage: 'Something went wrong. Please try again.',
retry: true
};
}
}
static async handleWithRetry(apiCall, maxRetries = 3) {
for (let attempt = 1; attempt <= maxRetries; attempt++) {
try {
return await apiCall();
} catch (error) {
const handling = this.handleAuthError(error);
if (!handling.retry || attempt === maxRetries) {
throw error;
}
const delay = handling.delay || Math.pow(2, attempt) * 1000;
await new Promise(resolve => setTimeout(resolve, delay));
}
}
}
}
Testing Your Integration
Authentication Flow Tests
async function testAuthenticationFlow() {
const authManager = new CashInAuthManager('sk_test_your_test_key');
console.log('Testing authentication initialization...');
const initResult = await authManager.initialize();
console.log('Init result:', initResult);
console.log('Testing signup flow...');
const signupResult = await handleUserSignup({
email: 'test@example.com',
name: 'Test User',
handle: 'testuser123'
});
console.log('Signup result:', signupResult);
console.log('Testing signin flow...');
const signinManager = new SigninFlowManager();
const signinResult = await signinManager.initiateSignin('test@example.com');
console.log('Signin result:', signinResult);
console.log('Testing signout...');
const signoutResult = await authManager.signout();
console.log('Signout result:', signoutResult);
}
// Run tests in development environment
if (process.env.NODE_ENV === 'development') {
window.testAuth = testAuthenticationFlow;
}
Best Practices
Security Considerations
-
Always validate user input before sending to APIs
-
Store minimal user data in localStorage
-
Clear sensitive data on signout or page close
-
Use HTTPS for all authentication requests
-
Implement proper CSRF protection
-
Validate instance states before critical operations
Performance Optimization
-
Cache authentication context checks for short periods
-
Debounce verification code resend requests
-
Preload authentication UI components
-
Use session storage for temporary verification states
-
Implement proper loading states for all auth operations
User Experience Guidelines
-
Minimize required fields during signup
-
Provide clear error messages with actionable steps
-
Show progress indicators during multi-step flows
-
Offer multiple verification methods when available
-
Remember user preferences (email vs phone verification)
-
Implement graceful degradation for failed auth operations
This integration guide provides comprehensive patterns for implementing CashIn's Authentication endpoints while maintaining excellent user experience and robust error handling.
Authentication Endpoint Summary
User Signup
-
Use Case: New user registration with campaign attribution
-
Returns: Complete user profile, migrated instance ID
-
Instance Effect: Upgrades anonymous instance to authenticated
-
Handles: Email conflicts, validation errors
Signin Initiation
-
Use Case: Start login process for existing users
-
Returns: User found status, available verification methods
-
Methods: Email, SMS, push notifications
-
Handles: Non-existent users, partner relationship validation
Signin Verification
-
Use Case: Complete authentication with code/password
-
Returns: Full user data, insider status, partner-specific rules
-
Types: Verification code, password authentication
-
Instance Effect: Upgrades instance to authenticated state
Resend Verification
-
Use Case: Re-send codes during signin process
-
Returns: Confirmation of sent methods
-
Methods: Can specify email, SMS, or both
-
Limitation: Tied to active signin session
User Signout
-
Use Case: Clean session termination
-
Returns: Success confirmation
-
Instance Effect: Revokes and invalidates instance
-
Security: Clears all session data
Authentication Context
-
Use Case: Smart auto-authentication for returning users
-
Returns: Authentication eligibility, discount/campaign data
-
Factors: Device fingerprint, URL context, match strength
-
Integration Types:
cashin_app,mobile_app,web_link,external_link