Authentication Flows via API
Learn how to implement complete authentication flows using the PasskeyMe REST API directly, without using our SDKs.
🔄 Complete OAuth Flow
Step 1: Get Application Configuration
First, retrieve your application's OAuth configuration:
async function getAppConfig(appId) {
const response = await fetch(
`https://auth.passkeyme.com/api/config?app_id=${appId}`
);
const config = await response.json();
return {
providers: config.oauth_providers, // ['google', 'github', 'facebook']
redirectUri: config.redirect_uri,
appName: config.app_name
};
}
Step 2: Initiate OAuth Flow
Redirect users to the OAuth provider:
function redirectToOAuth(provider, appId, redirectUri, state = null) {
const params = new URLSearchParams({
app_id: appId,
redirect_uri: redirectUri
});
if (state) {
params.append('state', state);
}
const oauthUrl = `https://auth.passkeyme.com/oauth/${provider}/authorize?${params}`;
window.location.href = oauthUrl;
}
// Usage
redirectToOAuth('google', 'your-app-id', 'https://yourapp.com/auth/callback');
Step 3: Handle OAuth Callback
Process the authentication callback:
async function handleAuthCallback() {
const urlParams = new URLSearchParams(window.location.search);
const token = urlParams.get('token');
const error = urlParams.get('error');
if (error) {
throw new Error(`Authentication failed: ${error}`);
}
if (!token) {
throw new Error('No token received');
}
// Verify the token
const verification = await verifyToken(token);
if (verification.valid) {
// Store token securely
localStorage.setItem('passkeyme_token', token);
// Get user information
const user = await getCurrentUser(token);
return { token, user };
} else {
throw new Error('Invalid token received');
}
}
Step 4: Token Verification
Verify received tokens:
async function verifyToken(token, appId) {
const response = await fetch(
`https://auth.passkeyme.com/api/auth/verify-token?token=${token}&app_id=${appId}`
);
const result = await response.json();
return {
valid: result.valid,
user: result.user,
expires: result.expires
};
}
Step 5: Get User Information
Retrieve authenticated user details:
async function getCurrentUser(token) {
const response = await fetch(
`https://auth.passkeyme.com/api/user?token=${token}`
);
const user = await response.json();
return {
id: user.id,
email: user.email,
name: user.name,
picture: user.avatar,
emailVerified: user.email_verified,
hasPasskey: user.has_passkey,
createdAt: user.created_at,
lastLoginAt: user.last_login_at
};
}
🔐 Passkey Registration Flow
Step 1: Check Passkey Support
function isPasskeySupported() {
return window.PublicKeyCredential &&
window.PublicKeyCredential.isUserVerifyingPlatformAuthenticatorAvailable;
}
async function checkPasskeyAvailability() {
if (!isPasskeySupported()) {
return false;
}
try {
return await PublicKeyCredential.isUserVerifyingPlatformAuthenticatorAvailable();
} catch (error) {
return false;
}
}
Step 2: Register Passkey
async function registerPasskey(token) {
// Get registration challenge from PasskeyMe API
const challengeResponse = await fetch(
`https://auth.passkeyme.com/api/passkey/register/challenge?token=${token}`
);
const challenge = await challengeResponse.json();
// Create passkey with browser WebAuthn API
const credential = await navigator.credentials.create({
publicKey: challenge.publicKey
});
// Send credential back to PasskeyMe
const registrationResponse = await fetch(
`https://auth.passkeyme.com/api/passkey/register/complete`,
{
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${token}`
},
body: JSON.stringify({
credential: {
id: credential.id,
rawId: Array.from(new Uint8Array(credential.rawId)),
response: {
clientDataJSON: Array.from(new Uint8Array(credential.response.clientDataJSON)),
attestationObject: Array.from(new Uint8Array(credential.response.attestationObject))
},
type: credential.type
}
})
}
);
return registrationResponse.json();
}
Step 3: Authenticate with Passkey
async function authenticateWithPasskey(appId) {
// Get authentication challenge
const challengeResponse = await fetch(
`https://auth.passkeyme.com/api/passkey/auth/challenge?app_id=${appId}`
);
const challenge = await challengeResponse.json();
// Authenticate with browser WebAuthn API
const assertion = await navigator.credentials.get({
publicKey: challenge.publicKey
});
// Send assertion to PasskeyMe for verification
const authResponse = await fetch(
`https://auth.passkeyme.com/api/passkey/auth/complete`,
{
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
assertion: {
id: assertion.id,
rawId: Array.from(new Uint8Array(assertion.rawId)),
response: {
clientDataJSON: Array.from(new Uint8Array(assertion.response.clientDataJSON)),
authenticatorData: Array.from(new Uint8Array(assertion.response.authenticatorData)),
signature: Array.from(new Uint8Array(assertion.response.signature)),
userHandle: assertion.response.userHandle ?
Array.from(new Uint8Array(assertion.response.userHandle)) : null
},
type: assertion.type
},
app_id: appId
})
}
);
const result = await authResponse.json();
if (result.success) {
return {
token: result.token,
user: result.user
};
} else {
throw new Error(result.error || 'Passkey authentication failed');
}
}
🛡️ Error Handling
Common API Errors
class PasskeymeApiError extends Error {
constructor(response, message) {
super(message);
this.response = response;
this.statusCode = response.status;
}
}
async function apiCall(url, options = {}) {
try {
const response = await fetch(url, {
...options,
headers: {
'Content-Type': 'application/json',
...options.headers
}
});
if (!response.ok) {
const errorData = await response.json().catch(() => ({}));
throw new PasskeymeApiError(
response,
errorData.error || `HTTP ${response.status}: ${response.statusText}`
);
}
return response.json();
} catch (error) {
if (error instanceof PasskeymeApiError) {
throw error;
}
// Network or other errors
throw new Error(`API call failed: ${error.message}`);
}
}
// Usage with error handling
try {
const user = await getCurrentUser(token);
console.log('User:', user);
} catch (error) {
if (error instanceof PasskeymeApiError) {
if (error.statusCode === 401) {
// Token expired or invalid
handleTokenExpired();
} else if (error.statusCode === 404) {
// User not found
handleUserNotFound();
}
} else {
// Network or other errors
console.error('Unexpected error:', error);
}
}
🔄 Token Refresh Implementation
class TokenManager {
constructor(appId) {
this.appId = appId;
this.token = localStorage.getItem('passkeyme_token');
this.refreshPromise = null;
}
async getValidToken() {
if (!this.token) {
throw new Error('No token available');
}
// Check if token is still valid
const verification = await this.verifyToken();
if (verification.valid) {
return this.token;
}
// Token expired, need to re-authenticate
this.clearToken();
throw new Error('Token expired, re-authentication required');
}
async verifyToken() {
if (!this.token) return { valid: false };
try {
const result = await apiCall(
`https://auth.passkeyme.com/api/auth/verify-token?token=${this.token}&app_id=${this.appId}`
);
return result;
} catch (error) {
return { valid: false };
}
}
setToken(token) {
this.token = token;
localStorage.setItem('passkeyme_token', token);
}
clearToken() {
this.token = null;
localStorage.removeItem('passkeyme_token');
}
}
📱 Complete Implementation Example
Here's a complete authentication manager using the PasskeyMe API:
class PasskeymeAuth {
constructor(appId, redirectUri) {
this.appId = appId;
this.redirectUri = redirectUri;
this.tokenManager = new TokenManager(appId);
this.baseUrl = 'https://auth.passkeyme.com';
}
// OAuth Authentication
async signInWithOAuth(provider) {
const state = this.generateState();
sessionStorage.setItem('auth_state', state);
redirectToOAuth(provider, this.appId, this.redirectUri, state);
}
// Handle OAuth callback
async handleCallback() {
const result = await handleAuthCallback();
this.tokenManager.setToken(result.token);
return result.user;
}
// Passkey authentication
async signInWithPasskey() {
const result = await authenticateWithPasskey(this.appId);
this.tokenManager.setToken(result.token);
return result.user;
}
// Register passkey
async registerPasskey() {
const token = await this.tokenManager.getValidToken();
return registerPasskey(token);
}
// Get current user
async getCurrentUser() {
const token = await this.tokenManager.getValidToken();
return getCurrentUser(token);
}
// Check authentication status
async isAuthenticated() {
try {
const verification = await this.tokenManager.verifyToken();
return verification.valid;
} catch {
return false;
}
}
// Sign out
signOut() {
this.tokenManager.clearToken();
}
// Utility methods
generateState() {
return Math.random().toString(36).substring(2, 15) +
Math.random().toString(36).substring(2, 15);
}
}
// Usage
const auth = new PasskeymeAuth('your-app-id', 'https://yourapp.com/auth/callback');
// OAuth sign in
await auth.signInWithOAuth('google');
// Passkey sign in (if available)
if (await checkPasskeyAvailability()) {
await auth.signInWithPasskey();
}
// Get current user
const user = await auth.getCurrentUser();
🔗 Next Steps
- API Overview - When to use API vs SDKs
- Token Management - Security and lifecycle management
- API Reference - Complete endpoint documentation
- SDK Integration - Use pre-built SDKs instead
- Security Model - Security best practices