UNPKG

@bynn-intelligence/agemin-sdk

Version:

agemin.com SDK for age verification

1,093 lines (858 loc) 33.5 kB
# Agemin SDK [![npm version](https://img.shields.io/npm/v/@bynn-intelligence/agemin-sdk.svg)](https://www.npmjs.com/package/@bynn-intelligence/agemin-sdk) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) A secure, type-safe JavaScript/TypeScript SDK for integrating Agemin biometric age verification into your web applications. > **🔒 Security-First Design**: This SDK uses a secure architecture where verification results are only accessible server-side using your private API key, preventing abuse and ensuring billing security. > **📝 Prerequisites**: > 1. Create a free account on [agemin.com](https://agemin.com) > 2. Get your **Asset ID** from [agemin.com/app/websites](https://agemin.com/app/websites) (format: `asset_5b08b274353b92f4`) > 3. Get your **Private Key** from [agemin.com/app/api-keys](https://agemin.com/app/api-keys) > 4. Keep your Private Key secure on your backend server ## Features - 🚀 **Easy Integration** - Simple API with automatic initialization support - 📱 **Cross-Platform** - Works on desktop and mobile browsers - 🎨 **Customizable** - Theme support (light/dark/auto) and localization - 🔒 **Secure** - Cross-origin communication with trusted domain validation - 📦 **Lightweight** - Zero runtime dependencies - 💪 **TypeScript** - Full TypeScript support with comprehensive type definitions - 🎯 **Flexible** - Multiple verification modes (modal, popup, redirect) - ⚛️ **React Compatible** - Singleton pattern prevents duplicate modals in StrictMode (v5.0+) ## Getting Started 1. **Sign up for a free account** at [agemin.com](https://agemin.com) 2. **Get your Asset ID** at [agemin.com/app/websites](https://agemin.com/app/websites) - Each website/app has a unique Asset ID (e.g., `asset_5b08b274353b92f4`) - Use this Asset ID in your frontend SDK 3. **Get your Private Key** at [agemin.com/app/api-keys](https://agemin.com/app/api-keys) - Keep this secure on your backend only 4. **Install the SDK** using your preferred package manager 5. **Generate reference IDs** server-side for each verification 6. **Initialize SDK** with Asset ID and Reference ID 7. **Verify results** server-side using your Private Key ## Installation ### NPM ```bash npm install @bynn-intelligence/agemin-sdk ``` ### Yarn ```bash yarn add @bynn-intelligence/agemin-sdk ``` ### pnpm ```bash pnpm add @bynn-intelligence/agemin-sdk ``` ### CDN ```html <!-- Latest version --> <script src="https://unpkg.com/@bynn-intelligence/agemin-sdk/dist/agemin-sdk.umd.js"></script> <!-- Specific version --> <script src="https://unpkg.com/@bynn-intelligence/agemin-sdk@2.0.1/dist/agemin-sdk.umd.js"></script> <!-- Minified version --> <script src="https://unpkg.com/@bynn-intelligence/agemin-sdk/dist/agemin-sdk.min.js"></script> ``` ## Quick Start ### Frontend Implementation ```javascript import Agemin from '@bynn-intelligence/agemin-sdk'; // 1. Get reference ID from your backend const response = await fetch('/api/agemin/reference', { method: 'POST' }); const { referenceId } = await response.json(); // 2. Initialize SDK with Asset ID and Reference ID // Note: In v5.x, only the first call creates an instance const agemin = new Agemin({ assetId: 'ast_5b08b274353b92f4', // Your Asset ID from agemin.com/app/websites referenceId: referenceId, // Unique reference ID from your backend (max 50 bytes) metadata: { userId: 123 }, // Optional metadata (max 256 bytes when stringified) debug: true }); // Alternative: Use getInstance() to get existing instance const agemin = Agemin.getInstance(); // Get existing instance // or create if doesn't exist: const agemin = Agemin.getInstance(config); // 3. Optional: Register event listeners for real-time updates agemin.onAppReady(() => { console.log('Verification app loaded successfully'); }); agemin.onProgress((data) => { console.log(`Progress: ${data.percentage}% - ${data.stage}`); // Update your UI with progress information }); agemin.onStateChange((data) => { console.log(`State changed from ${data.from} to ${data.to}`); }); agemin.onUserAction((data) => { console.log(`User action: ${data.type} on ${data.target}`); // Track user interactions for analytics }); // 4. Start verification agemin.verify({ onSuccess: (result) => { // Verification process completed (doesn't mean user passed) // If using strong API security, check results server-side console.log('Verification completed:', result.referenceId); }, onAgePass: (result) => { // User passed age verification (JWT present and is_of_age = true) console.log('Age verification passed'); window.location.href = '/protected-content'; }, onAgeFail: (result) => { // User failed age verification (JWT present but is_of_age = false) console.log('Age verification failed'); window.location.href = '/age-restricted'; }, onError: (error) => { // Technical error - show fallback console.error('Technical error:', error); showFallbackAgeModal(); }, onCancel: () => { console.log('User cancelled verification'); } }); ``` ### Age Gating Every Page To ensure all your pages are properly age-gated, use the `validateSession` method at the top of each protected page: ```javascript // On every age-restricted page const agemin = new Agemin({ assetId: 'ast_A6ctvqk5egQtCoZhr5LrWkRm', referenceId: 'unique-reference-id' // Use visitor ID, session ID, or UUID }); // Check for existing valid session or launch verification const result = await agemin.validateSession({ onSuccess: (data) => { console.log('Verification completed'); // For strong API security, verify server-side }, onAgePass: (data) => { console.log('User is age verified'); // Allow access to content }, onAgeFail: (data) => { console.log('User did not meet age requirement'); // Redirect to age-restricted page window.location.href = '/age-restricted'; }, onError: (err) => { console.error('Verification error:', err); // Show fallback age gate showFallbackAgeModal(); } }); // If result is true, user already has valid session if (result === true) { console.log('User already age verified from previous session'); // Content is accessible } ``` The `validateSession` method will: - Return `true` immediately if a valid age verification cookie exists - Automatically launch verification if: - No verification cookie exists - The JWT is expired or invalid - The user previously failed age verification ### React Integration (v5.0+ Singleton Pattern) The SDK v5.0+ uses a singleton pattern to prevent duplicate modals in React StrictMode: ```javascript import { useEffect, useRef } from 'react'; import Agemin from '@bynn-intelligence/agemin-sdk'; function AgeGate({ children }) { const initialized = useRef(false); useEffect(() => { // React StrictMode will call this twice, but SDK handles it if (initialized.current) return; initialized.current = true; // Create Agemin instance (singleton - only first call creates instance) const agemin = new Agemin({ assetId: 'ast_A6ctvqk5egQtCoZhr5LrWkRm', referenceId: generateUniqueId(), debug: true }); // Validate session agemin.validateSession({ onAgePass: () => { console.log('User is verified'); }, onAgeFail: () => { window.location.href = '/age-restricted'; } }); // Cleanup (optional - for testing) return () => { // Only reset if you need to create a new instance // Agemin.reset(); }; }, []); return children; } ``` **Key Points for React:** - The SDK automatically handles multiple `new Agemin()` calls by returning the same instance - Only one verification modal will ever be shown, even in StrictMode - Use `Agemin.reset()` only when you need to create a completely new instance - The singleton pattern prevents race conditions and duplicate modals ### Backend Implementation (Node.js Example) (optional but more secure) ```javascript // Generate reference endpoint app.post('/api/agemin/reference', (req, res) => { // Generate unique reference ID const referenceId = crypto.randomUUID(); // Store reference in database with user context await db.references.create({ id: referenceId, userId: req.user?.id, createdAt: new Date() }); res.json({ referenceId }); }); // Verify result endpoint app.post('/api/agemin/verify', async (req, res) => { const { referenceId } = req.body; // Fetch verification result from Agemin API using Private Key const result = await fetch(`https://api.agemin.com/v1/agemin/result?referenceId=${referenceId}`, { headers: { 'Authorization': `Bearer ${process.env.AGEMIN_PRIVATE_KEY}` // Private key from agemin.com/app/api-keys } }); const verification = await result.json(); // Check if user meets age requirement const verified = verification.status === 'verified'; // Update reference in database await db.references.update(referenceId, { verified, completedAt: new Date() }); res.json({ verified, age: verification.age // Only if needed }); }); ``` ### Auto-Initialization You can configure the SDK directly in HTML using data attributes: ```html <script src="https://unpkg.com/@bynn-intelligence/agemin-sdk/dist/agemin-sdk.min.js" data-agemin-asset-id="ast_5b08b274353b92f4" data-agemin-reference-id="unique-reference-id" data-agemin-theme="auto" data-agemin-locale="en" data-agemin-debug="true"> </script> <!-- Any button with data-agemin-trigger will automatically start verification --> <button data-agemin-trigger>Verify My Age</button> ``` **Note**: The reference ID must be generated server-side and injected into the HTML for security. ## Configuration Options ### SDK Initialization ```typescript const agemin = new Agemin({ // Required assetId: string; // Your Asset ID from agemin.com/app/websites (e.g., 'ast_5b08b274353b92f4') referenceId: string; // Unique reference ID (max 50 bytes, generate server-side) // Optional metadata?: Record<string, any>; // Custom metadata (max 256 bytes when stringified) baseUrl?: string; // Custom verification URL (default: 'https://verify.agemin.com') theme?: 'light' | 'dark' | 'auto'; // UI theme (default: 'auto') locale?: string; // Language locale (default: 'en') errorUrl?: string; // URL to redirect on error successUrl?: string; // URL to redirect on success cancelUrl?: string; // URL to redirect on cancellation debug?: boolean; // Enable debug logging (default: false) allowSearchEngineBypass?: boolean; // Allow search engines to bypass age verification (default: false) searchEngineDetection?: 'ua' | 'headless' | 'cookies' | 'combined' | 'strict'; // Detection mode (default: 'ua') }); ``` **Size Limits**: - `referenceId`: Maximum 50 bytes - `metadata`: Maximum 256 bytes when JSON stringified These limits ensure efficient data transmission and prevent abuse. ### SEO Configuration - Search Engine Bypass For SEO optimization, you can allow search engine crawlers to bypass age verification while keeping it active for regular users: ```javascript const agemin = new Agemin({ assetId: 'ast_xxx', referenceId: 'ref_xxx', allowSearchEngineBypass: true, // Enable bypass for crawlers searchEngineDetection: 'combined' // Detection mode (default: 'ua') }); // When validateSession() is called: // - Search engines → Automatic bypass, returns true // - Regular users → Normal age verification flow ``` #### Detection Modes The SDK offers multiple crawler detection strategies to balance accuracy and performance: | Mode | Description | Use Case | |------|-------------|----------| | `'ua'` | User agent string detection only | **Default.** Fast, reliable for most crawlers | | `'headless'` | Detects headless browser characteristics | Catches sophisticated crawlers using headless Chrome | | `'cookies'` | Checks if cookies are supported | Googlebot typically doesn't support cookies | | `'combined'` | Any detection method triggers bypass | **Most inclusive.** Best for SEO but may have false positives | | `'strict'` | Requires multiple detection signals | **Most accurate.** Reduces false positives | #### Detection Methods Explained **1. User Agent Detection (`'ua'`)** - Checks for known crawler patterns in user agent string - Covers Google, Bing, social media bots, SEO tools - Fast but can be spoofed **2. Headless Browser Detection (`'headless'`)** - Checks navigator.plugins.length === 0 - Checks empty navigator.languages - Detects WebGL signatures (Mesa OffScreen, SwiftShader) - Effective against headless Chrome/Puppeteer **3. Cookie Support Detection (`'cookies'`)** - Tests if browser can set/read cookies - Googlebot generally doesn't support cookies - May trigger on privacy-focused users **4. Combined Detection (`'combined'`)** - Uses OR logic: any method detecting a bot triggers bypass - Best for maximum SEO coverage - May bypass for some privacy-conscious users **5. Strict Detection (`'strict'`)** - Requires bot user agent AND (headless OR no cookies) - Minimizes false positives - May miss some legitimate crawlers #### Example Configurations ```javascript // Maximum SEO coverage (recommended for content sites) const agemin = new Agemin({ assetId: 'ast_xxx', referenceId: 'ref_xxx', allowSearchEngineBypass: true, searchEngineDetection: 'combined' }); // Balanced approach (default) const agemin = new Agemin({ assetId: 'ast_xxx', referenceId: 'ref_xxx', allowSearchEngineBypass: true // searchEngineDetection defaults to 'ua' }); // Strict validation (e-commerce, sensitive content) const agemin = new Agemin({ assetId: 'ast_xxx', referenceId: 'ref_xxx', allowSearchEngineBypass: true, searchEngineDetection: 'strict' }); ``` **Important Notes:** - Detection results are cached for 1 minute to improve performance - This only affects client-side validation - Search engines still won't have valid JWT cookies for server-side verification - Test with Google's Mobile-Friendly Test tool to verify your configuration ### Verification Options ```typescript agemin.verify({ // Display mode mode?: 'modal' | 'redirect'; // How to show verification (default: modal) // Callbacks onSuccess?: (result: VerificationResult) => void; // Verification completed (process finished) onAgePass?: (result: VerificationResult) => void; // User passed age check (JWT present, is_of_age = true) onAgeFail?: (result: VerificationResult) => void; // User failed age check (JWT present, is_of_age = false) onError?: (error: VerificationError) => void; // Technical error (API, network, etc.) onCancel?: () => void; // User cancelled verification onClose?: () => void; // Modal closed // Customization theme?: 'light' | 'dark' | 'auto'; // Override default theme locale?: string; // Override default locale (use 'auto' for browser detection) metadata?: Record<string, any>; // Custom metadata to attach }); ``` ### VerificationResult Object ```typescript interface VerificationResult { referenceId: string; // Reference ID to verify on backend completed: boolean; // Verification process completed timestamp: number; // Completion timestamp } ``` **Important**: The `onSuccess` callback only indicates the verification process completed. It does NOT mean the user passed the age check. Use `onAgePass` and `onAgeFail` for age-specific results, or verify server-side using your Private Key for strong API security. ## Event Listeners The SDK provides event listeners for real-time updates during the verification process: ### `onAppReady(callback)` Called when the verification app has loaded and is ready. ```javascript agemin.onAppReady(() => { console.log('App is ready'); // Hide loading spinner, enable buttons, etc. }); ``` ### `onProgress(callback)` Receive real-time progress updates during face scanning. ```javascript agemin.onProgress((data) => { console.log(`Progress: ${data.percentage}%`); console.log(`Stage: ${data.stage}`); // e.g., "Hold still", "Move closer" console.log(`Message: ${data.message}`); // e.g., "Capture 3/5" // Update your progress bar updateProgressBar(data.percentage); }); ``` ### `onStateChange(callback)` Track state transitions in the verification flow. ```javascript agemin.onStateChange((data) => { console.log(`From: ${data.from}`); console.log(`To: ${data.to}`); console.log(`Data: ${data.data}`); // Handle state-specific logic if (data.to === 'completed') { showSuccessMessage(); } }); ``` ### `onUserAction(callback)` Monitor user interactions for analytics or UX improvements. ```javascript agemin.onUserAction((data) => { console.log(`Action: ${data.type}`); // e.g., "cancel", "click" console.log(`Target: ${data.target}`); // e.g., "consent_page", "face_scan_page" // Track with analytics analytics.track('agemin_user_action', data); }); ``` ## API Reference ### Methods #### `verify(options?: VerifyOptions): string` Starts the verification process. Returns the reference ID. #### `validateSession(options?: VerifyOptions): Promise<boolean | string>` Validates if a user has a valid age verification session stored in cookies. - Returns `true` if a valid session exists and the user is of age - Automatically launches verification and returns the reference ID if: - No verification cookie exists - The JWT token is expired - The JWT signature is invalid - The user is not of age (`is_of_age: false`) This method is useful for automatically checking and maintaining age verification across page loads: ```javascript // Simple usage - automatically handles everything const result = await agemin.validateSession(); if (result === true) { // User already age verified, allow access console.log('User has valid age verification'); } else { // Verification was launched, result is the referenceId console.log('Verification launched with ID:', result); } // With callbacks for the verification flow const result = await agemin.validateSession({ onSuccess: (data) => { console.log('Age verification successful'); // User is now verified }, onError: (err) => { console.error('Verification error:', err); // Show fallback age gate } }); ``` **Note:** This method requires cookies to be enabled. The verification is stored as a JWT in the `agemin_verification` cookie, with the duration controlled by your website's security settings in the Agemin dashboard. #### `close(): void` Programmatically closes the verification modal/popup. #### `isOpen(): boolean` Checks if a verification session is currently active. #### `getReferenceId(): string` Returns the reference ID for the current verification. ### Static Methods #### `Agemin.version: string` Returns the SDK version. #### `Agemin.isSupported(): boolean` Checks if the current browser is supported. ## TypeScript Support The SDK includes comprehensive TypeScript definitions: ```typescript import Agemin, { AgeminConfig, VerifyOptions, VerificationResult, VerificationError } from '@bynn-intelligence/agemin-sdk'; // Full type safety and IntelliSense support const config: AgeminConfig = { assetId: 'asset_5b08b274353b92f4', referenceId: 'unique-reference-id', // Required: generate server-side theme: 'dark' }; const agemin = new Agemin(config); ``` ## Verification Modes ### Modal (Default) Opens verification in an iframe overlay within the current page. Works seamlessly on both desktop and mobile devices. ```javascript agemin.verify({ mode: 'modal' }); ``` ### Redirect Redirects the entire page to the verification URL. Useful for single-page flows or when iframe is not suitable. ```javascript agemin.verify({ mode: 'redirect' }); ``` ## Event Handling The SDK provides comprehensive event callbacks for different scenarios: ```javascript agemin.verify({ onSuccess: (result) => { // Verification process completed successfully console.log('Reference ID:', result.referenceId); console.log('Completed:', result.completed); // true // Note: This doesn't indicate if user passed age check // For strong API security, verify results server-side }, onAgePass: (result) => { // User passed age verification (JWT present and is_of_age = true) console.log('User meets age requirement'); // Allow access to age-restricted content }, onAgeFail: (result) => { // User failed age verification (JWT present but is_of_age = false) console.log('User does not meet age requirement'); // Redirect to age-appropriate content or show restriction message }, onError: (error) => { // Technical error occurred (API, network, model error, etc.) console.error('Error code:', error.code); console.error('Error message:', error.message); // IMPORTANT: Show fallback age confirmation to avoid losing visitors // Example: Display a simple "Are you 18+" modal as backup showBackupAgeGate(); }, onCancel: () => { // User explicitly cancelled the verification process console.log('User cancelled'); }, onClose: () => { // Modal/popup was closed (fired after other callbacks) console.log('Verification window closed'); } }); ``` ### Important: Handling Technical Errors When `onError` is triggered (technical issues), we strongly recommend showing a fallback age confirmation modal to ensure you don't lose potential visitors due to temporary technical issues: ```javascript function showBackupAgeGate() { // Simple fallback when Agemin verification has technical issues const confirmed = confirm('Please confirm you are 18 or older to continue'); if (confirmed) { // Allow access with degraded verification allowAccess(); } else { // Redirect to age-appropriate content window.location.href = '/underage'; } } ``` ## Examples ### React Integration ```jsx import React, { useEffect, useState } from 'react'; import Agemin from '@bynn-intelligence/agemin-sdk'; function AgeVerification() { const [agemin, setAgemin] = useState(null); const [isVerified, setIsVerified] = useState(false); useEffect(() => { const sdk = new Agemin({ assetId: process.env.REACT_APP_AGEMIN_ASSET_ID, referenceId: generateUniqueId() // Required: generate unique ID }); setAgemin(sdk); }, []); const handleVerify = () => { agemin?.verify({ onSuccess: (result) => { console.log('Verification completed'); // For strong API security, verify results server-side }, onAgePass: (result) => { setIsVerified(true); // User passed age verification }, onAgeFail: (result) => { // User is underage alert('You must be 18 or older to access this content'); window.location.href = '/age-restricted'; }, onError: (error) => { // Technical error - show fallback if (confirm('Please confirm you are 18 or older')) { setIsVerified(true); } } }); }; return ( <div> {!isVerified ? ( <button onClick={handleVerify}>Verify Age</button> ) : ( <p>✅ Age verified!</p> )} </div> ); } ``` ### Vue.js Integration ```vue <template> <div> <button @click="verifyAge" v-if="!isVerified"> Verify Age </button> <p v-else>✅ Age verified!</p> </div> </template> <script> import Agemin from '@bynn-intelligence/agemin-sdk'; export default { data() { return { agemin: null, isVerified: false }; }, mounted() { this.agemin = new Agemin({ assetId: process.env.VUE_APP_AGEMIN_ASSET_ID, referenceId: this.generateUniqueId() // Required: generate unique ID }); }, methods: { verifyAge() { this.agemin.verify({ onSuccess: (result) => { console.log('Verification completed'); }, onAgePass: (result) => { this.isVerified = true; // User passed age verification }, onAgeFail: (result) => { alert('You must be 18 or older to access this content'); window.location.href = '/age-restricted'; }, onError: (error) => { alert(`Verification failed: ${error.message}`); } }); } } }; </script> ``` ### Custom Metadata You can attach custom metadata to verification sessions: ```javascript agemin.verify({ metadata: { source: 'checkout-page', productId: 'ABC123', userId: 'user-456', timestamp: Date.now() }, onSuccess: (result) => { // Metadata is included in the verification result console.log('Verification completed with metadata'); } }); ``` ## Browser Support The SDK supports all modern browsers: - Chrome 90+ - Firefox 88+ - Safari 14+ - Edge 90+ - Mobile Safari (iOS 14+) - Chrome Mobile (Android) ## Development ### Building from Source ```bash # Clone the repository git clone https://github.com/Bynn-Intelligence/agemin-sdk.git cd agemin-sdk # Install dependencies npm install # Build the SDK npm run build # Watch mode for development npm run dev ``` ### Running Examples ```bash # Build the SDK first npm run build # Open an example in your browser open examples/basic.html ``` ## Security Architecture ### Why Server-Side Verification? This SDK uses a secure two-step verification process: 1. **Frontend** handles the UI/UX of age verification 2. **Backend** fetches and validates the actual results This architecture prevents: - **Billing fraud**: Others can't use your Asset ID without your knowledge - **Result tampering**: Verification results can't be faked client-side - **API key exposure**: Your Private Key never leaves your server ### Security Flow ```mermaid sequenceDiagram participant User participant Frontend participant YourBackend participant AgeminAPI User->>Frontend: Initiate verification Frontend->>YourBackend: Request session ID YourBackend->>Frontend: Return unique session ID Frontend->>AgeminAPI: Start verification (Asset ID + Session ID) User->>AgeminAPI: Complete verification AgeminAPI->>Frontend: Verification completed Frontend->>YourBackend: Check result (Session ID) YourBackend->>AgeminAPI: GET /result (Private Key + Session ID) AgeminAPI->>YourBackend: Return actual result YourBackend->>Frontend: Return verified/not verified ``` ### API Keys - **Asset ID**: Get from [agemin.com/app/websites](https://agemin.com/app/websites) - Each website/app has a unique Asset ID (format: `asset_5b08b274353b92f4`) - Safe to use in frontend code - **Private Key**: Get from [agemin.com/app/api-keys](https://agemin.com/app/api-keys) - NEVER expose in frontend code, keep on backend only ### Best Practices 1. **Generate Session IDs server-side**: Use cryptographically secure random generators 2. **Validate sessions**: Track sessions in your database to prevent replay attacks 3. **Set session expiry**: Expire unused sessions after a reasonable time 4. **Use HTTPS**: Always use HTTPS in production 5. **Secure your Private Key**: Store in environment variables, never commit to code ## Error Handling ### Technical Errors Technical errors trigger `onError` and should be handled with a fallback: ```javascript agemin.verify({ onError: (error) => { // Log the technical error for debugging console.error('Technical error:', error.code, error.message); // Show fallback age gate to avoid losing visitors switch (error.code) { case 'POPUP_BLOCKED': alert('Please allow popups for age verification'); showSimpleAgeGate(); break; case 'NETWORK_ERROR': case 'API_ERROR': case 'MODEL_ERROR': // Don't lose the visitor - show backup age confirmation showSimpleAgeGate(); break; default: showSimpleAgeGate(); } } }); function showSimpleAgeGate() { // Fallback for when Agemin verification has technical issues const isAdult = confirm('Are you 18 years or older?'); if (isAdult) { // Grant degraded access grantAccess(/* limited = */ true); } else { redirectToAgeAppropriate(); } } ``` ## Guide for AI Assistants (LLMs) This section helps AI assistants understand how to guide developers in integrating the Agemin SDK. ### What This SDK Does The Agemin SDK provides age verification through facial scanning. It offers two main methods for integration, each suited for different use cases. ### Two Ways to Verify Age #### Method 1: Manual Verification (`verify`) ``` User clicks button → Modal opens → Face scan → Result callbacks ``` **When to use:** User explicitly triggers verification (e.g., "Verify Age" button) **Callbacks flow:** - `onSuccess` - Always fires when verification completes - `onAgePass` - Fires if user meets age requirement - `onAgeFail` - Fires if user doesn't meet requirement - `onError` - Fires on technical problems - `onCancel` - Fires if user closes modal #### Method 2: Automatic Verification (`validateSession`) ``` Page loads → Check saved session → If valid: continue | If not: auto-launch verify ``` **When to use:** Protecting multiple pages automatically **Returns:** - `true` if user already verified (has valid session) - Launches verification modal if no valid session exists ### Simple Decision Guide ``` Single "Verify Age" button? → Use verify() Protect every page automatically? → Use validateSession() Want seamless multi-page experience? → Use validateSession() ``` ### Understanding the Callbacks ``` Verification Process Flow: ┌─────────────────┐ │ Verification │ │ Completes │ → onSuccess (always called) └────────┬────────┘ │ ┌────┴────┐ │ Result? │ └────┬────┘ │ ┌────┴────────────┐ │ │ ↓ ↓ onAgePass onAgeFail (Age met) (Age not met) Technical Error → onError User Closes → onCancel ``` ### Integration Checklist for AI Assistants When helping developers integrate this SDK: - [ ] **Asset ID**: Ensure developer has Asset ID from agemin.com/app/websites - [ ] **Reference ID**: Each verification needs a unique reference ID - [ ] **Choose method**: - Single button/trigger → Use `verify()` - Automatic page protection → Use `validateSession()` - [ ] **Prevent infinite loops**: Age-fail redirect pages must NOT be age-gated - [ ] **Session persistence**: `validateSession()` remembers users across pages - [ ] **Callback handling**: Implement appropriate callbacks for the use case ### Common Integration Patterns | Use Case | Recommended Method | Why | |----------|-------------------|-----| | E-commerce checkout | `validateSession()` | Seamless multi-step process | | Content website | `validateSession()` | Protects all restricted pages | | Single landing page | `verify()` | One-time verification | | Terms acceptance | `verify()` | Explicit user action | | Gaming platform | `validateSession()` | Persistent access control | ### Key Concepts to Explain 1. **Session Management**: The SDK handles session storage automatically - developers don't manage cookies or tokens 2. **Verification Flow**: - User's age is verified through face scanning - Result is stored securely - Future page visits check this stored result 3. **Security Models**: - **Strong API Security**: Results only available server-side (onSuccess fires, no age result in frontend) - **Standard Security**: Age result available in callbacks (onAgePass/onAgeFail) ### Common Pitfalls to Warn About 1. **Infinite Loop**: Never use `validateSession()` on the age-fail redirect page 2. **Unique IDs**: Each user needs a unique reference ID (use session ID or user ID) 3. **Method Confusion**: Don't use `verify()` for automatic page protection 4. **Callback Misunderstanding**: `onSuccess` ≠ user passed age check ### Guidance Summary When an LLM helps a developer: 1. First, understand if they need single-trigger or automatic protection 2. For automatic protection across pages → `validateSession()` 3. For button-triggered verification → `verify()` 4. Always warn about the infinite loop risk with age-fail pages 5. Emphasize that the SDK handles all session management internally ## License MIT License - see [LICENSE](LICENSE) file for details. ## Support - **Documentation**: [https://docs.agemin.com](https://docs.agemin.com) - **Issues**: [GitHub Issues](https://github.com/Bynn-Intelligence/agemin-sdk/issues) - **npm Package**: [https://www.npmjs.com/package/@bynn-intelligence/agemin-sdk](https://www.npmjs.com/package/@bynn-intelligence/agemin-sdk) - **Email**: support@agemin.com ## Contributing We welcome contributions! Please see our [Contributing Guide](CONTRIBUTING.md) for details. ## Changelog See [CHANGELOG.md](CHANGELOG.md) for a list of changes in each version.