Authentication
JWT token management, login flows, and authenticated requests with
@embarkai/core/auth.
The auth module handles the full authentication lifecycle: logging in via multiple providers, managing JWT tokens with automatic refresh, and making authenticated API requests.
Configuration
Before using any auth functions, configure the JWT module with your API endpoint and token storage:
import {
configureJwtModule,
LocalStorageAdapter,
MemoryStorageAdapter,
} from '@embarkai/core'
// Browser environment
configureJwtModule({
apiUrl: 'https://api.lumiapassport.com',
storage: new LocalStorageAdapter(),
})
// Node.js / testing environment
configureJwtModule({
apiUrl: 'https://api.lumiapassport.com',
storage: new MemoryStorageAdapter(),
})Login Methods
Login with User ID
The simplest login method — authenticates directly with a user identifier:
import { loginWithUserId } from '@embarkai/core'
const response = await loginWithUserId('user_abc123')
console.log('Access Token:', response.accessToken)
console.log('Has Keyshare:', response.hasKeyshare)
console.log('Is New User:', response.isNewUser)Login with Email
Two-step email verification flow:
import { loginWithEmail } from '@embarkai/core'
// Step 1: Request a verification code (sent to user's inbox)
// Step 2: Submit the code
const response = await loginWithEmail('user@example.com', '123456')
console.log('User ID:', response.userId)Login with Telegram
Authenticate using Telegram login widget data:
import { loginWithTelegram } from '@embarkai/core'
const response = await loginWithTelegram({
id: 123456789,
first_name: 'Alice',
auth_date: 1700000000,
hash: 'telegram_auth_hash...',
})Login Response
All login methods return a LoginResponse:
| Field | Type | Description |
|---|---|---|
accessToken | string | Short-lived JWT for API calls |
refreshToken | string | Long-lived token for refreshing access |
userId | string | Unique user identifier |
expiresIn | number | Token TTL in seconds |
hasKeyshare | boolean | Whether the user has a TSS keyshare on the server |
isNewUser | boolean | undefined | true on first login |
avatar | string | null | User avatar URL |
displayName | string | null | User display name |
providers | string[] | Linked auth providers |
Token Management
JwtTokenManager
The JwtTokenManager class stores tokens and handles automatic refresh. Use the singleton or create your own instance:
import { jwtTokenManager, createJwtTokenManager } from '@embarkai/core'
// Singleton (configured via configureJwtModule)
const isLoggedIn = await jwtTokenManager.isAuthenticated()
const header = await jwtTokenManager.getAuthHeader()
// → { Authorization: 'Bearer eyJ...' }
// Custom instance
const manager = createJwtTokenManager({
apiUrl: 'https://api.lumiapassport.com',
storage: new MemoryStorageAdapter(),
})Key methods:
| Method | Returns | Description |
|---|---|---|
getAccessToken() | Promise<string | null> | Current access token |
getRefreshToken() | Promise<string | null> | Current refresh token |
getUserId() | Promise<string | null> | Authenticated user ID |
isTokenExpired() | Promise<boolean> | Check if access token is expired |
isAuthenticated() | Promise<boolean> | Check if user has valid tokens |
refreshAccessToken() | Promise<JwtTokens> | Force a token refresh |
getAuthHeader() | Promise<object> | Get Authorization header object |
clearTokens() | Promise<void> | Remove all stored tokens |
Token Storage
Implement the TokenStorage interface for custom storage backends:
import type { TokenStorage } from '@embarkai/core'
class SecureStorage implements TokenStorage {
async getItem(key: string): Promise<string | null> {
return await encrypted.get(key)
}
async setItem(key: string, value: string): Promise<void> {
await encrypted.set(key, value)
}
async removeItem(key: string): Promise<void> {
await encrypted.delete(key)
}
}Built-in adapters: LocalStorageAdapter (browser localStorage) and MemoryStorageAdapter (in-memory, non-persistent).
Utility Functions
Verify a Token
import { verifyToken } from '@embarkai/core'
const result = await verifyToken()
if (result.valid) {
console.log('User:', result.userId)
console.log('Session:', result.sessionId)
console.log('Has Keyshare:', result.hasKeyshare)
}Ensure Valid Token
Automatically refreshes the token if expired. Throws if refresh fails:
import { ensureValidToken } from '@embarkai/core'
await ensureValidToken()
// Access token is now guaranteed to be validGet Valid Tokens
Returns current tokens, refreshing first if needed:
import { getValidTokens } from '@embarkai/core'
const tokens = await getValidTokens()
console.log('User:', tokens.userId)
console.log('Expires at:', new Date(tokens.expiresAt * 1000))Authenticated Fetch
A drop-in wrapper around fetch that injects the Authorization header and auto-refreshes expired tokens:
import { authenticatedFetch } from '@embarkai/core'
const res = await authenticatedFetch('https://api.lumiapassport.com/me')
const user = await res.json()Logout
Clears all stored tokens:
import { logout } from '@embarkai/core'
await logout()Sync Keyshare Status
Re-checks whether the server holds a keyshare for the current user and updates stored token metadata:
import { syncKeyshareStatus } from '@embarkai/core'
await syncKeyshareStatus()Next Steps
- Server Wallets — create and manage MPC wallets after authentication
- Vault Backup — back up keyshares with password encryption
- Bundler — submit UserOperations with authenticated sessions