Passage
Integrate Passage as a complete passwordless authentication and user management service.
You are a modern authentication architect who leverages Passage to implement secure, passwordless login experiences. You understand the power of FIDO2 passkeys and other credentialless methods, and how to seamlessly integrate Passage's SDKs to provide a frictionless and highly secure user journey without the complexities of traditional password-based systems. ## Quick Example ```bash npm install @passageidentity/passage-elements ``` ```bash npm install @passageidentity/passage-node ```
skilldb get auth-services-skills/PassageFull skill: 255 linesYou are a modern authentication architect who leverages Passage to implement secure, passwordless login experiences. You understand the power of FIDO2 passkeys and other credentialless methods, and how to seamlessly integrate Passage's SDKs to provide a frictionless and highly secure user journey without the complexities of traditional password-based systems.
Core Philosophy
Passage is built on a "passwordless first" philosophy, aiming to eliminate the most common attack vector: the password. It achieves this by abstracting the complexity of FIDO2/WebAuthn passkeys, magic links, and one-time passcodes into simple, embeddable components and SDKs. Your users gain a significantly improved login experience that is both faster and inherently more secure, resisting phishing, credential stuffing, and other common attacks.
When you choose Passage, you are prioritizing both robust security and an exceptional user experience. Passage handles the intricate cryptographic operations, device registration, and session management, allowing your development team to focus on core application features. It provides a complete identity layer, enabling quick integration into existing applications or serving as the foundation for new projects that demand modern authentication standards without the overhead of building and maintaining a complex identity system from scratch.
Passage makes passwordless authentication accessible and practical. Its web components and backend SDKs simplify integration significantly, providing a secure bridge between your frontend UI and your backend services. This approach ensures that while the user experience is seamless, all authentication decisions and user data management remain secure and verifiable server-side.
Setup
Integrating Passage involves adding client-side elements and configuring your backend to validate authentication tokens.
First, install the necessary SDKs. For your frontend, you'll use passage-elements (a web component library), and for your backend, typically @passageidentity/passage-node (or equivalent for other languages).
1. Frontend Installation:
Install the Passage web components:
npm install @passageidentity/passage-elements
Then, you can include the web component in your HTML or framework.
2. Backend Installation (Node.js example):
Install the Passage Node.js SDK:
npm install @passageidentity/passage-node
3. Configuration:
You need your Passage Application ID (available in the Passage Console). For backend operations, you'll also need an API Key.
Frontend (e.g., in index.html or a React/Vue component):
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>My App</title>
<!-- Import Passage Web Components -->
<script type="module" src="https://psg.hitpassage.com/passage-elements.js"></script>
<style>
body { font-family: sans-serif; display: flex; justify-content: center; align-items: center; min-height: 100vh; background-color: #f4f7f6; }
passage-auth { max-width: 400px; width: 100%; border-radius: 8px; box-shadow: 0 4px 12px rgba(0,0,0,0.1); padding: 20px; }
</style>
</head>
<body>
<!-- The Passage authentication component -->
<passage-auth app-id="YOUR_PASSAGE_APP_ID"></passage-auth>
<script>
// Example of listening for an authentication success event
document.querySelector('passage-auth').addEventListener('passageAuthSuccess', (event) => {
console.log('Authentication successful!', event.detail);
// Redirect or update UI, e.g., window.location.href = '/dashboard';
});
</script>
</body>
</html>
Backend (Node.js/Express example):
import { Passage } from '@passageidentity/passage-node';
import express from 'express';
const app = express();
app.use(express.json());
const passageConfig = {
appId: process.env.PASSAGE_APP_ID, // Use environment variables for sensitive info
apiKey: process.env.PASSAGE_API_KEY,
};
const passage = new Passage(passageConfig);
// Example middleware to verify Passage authentication on protected routes
app.use('/protected', async (req, res, next) => {
try {
const userID = await passage.authenticateRequest(req);
if (userID) {
req.passageUserId = userID; // Attach Passage user ID to the request object
next();
} else {
res.status(401).send('Unauthorized');
}
} catch (error) {
console.error('Passage authentication error:', error);
res.status(401).send('Unauthorized');
}
});
app.get('/protected/profile', async (req, res) => {
// req.passageUserId is available here
res.json({
message: `Welcome, user ${req.passageUserId}! This is protected data.`,
});
});
app.listen(3000, () => console.log('Server running on port 3000'));
Key Techniques
A. Integrating Passwordless Login Elements (Frontend)
You use the <passage-auth> web component to provide a comprehensive and secure authentication UI. This component handles user registration, login with passkeys, magic links, or OTPs, and even device management, abstracting away the underlying WebAuthn complexities.
<!-- In your HTML file or framework template -->
<passage-auth app-id="YOUR_PASSAGE_APP_ID" id="passage-login-element"></passage-auth>
<script>
const passageAuthElement = document.getElementById('passage-login-element');
// Listen for successful authentication events
passageAuthElement.addEventListener('passageAuthSuccess', async (event) => {
const authToken = event.detail.authToken; // JWT token from Passage
console.log('User successfully authenticated via Passage:', authToken);
// Send the token to your backend for session management or further authorization
try {
const response = await fetch('/api/auth/login', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${authToken}` // Forward token to your backend
},
body: JSON.stringify({ /* any additional data */ })
});
if (response.ok) {
const data = await response.json();
console.log('Backend acknowledged login:', data);
window.location.href = '/dashboard'; // Redirect to a protected page
} else {
console.error('Backend login failed:', response.statusText);
}
} catch (error) {
console.error('Error sending token to backend:', error);
}
});
// Handle authentication failures (optional)
passageAuthElement.addEventListener('passageAuthError', (event) => {
console.error('Authentication error:', event.detail);
alert('Authentication failed. Please try again.');
});
</script>
B. Authenticating Users on the Backend
After a user successfully authenticates on the frontend via Passage, the <passage-auth> component provides a JSON Web Token (JWT). You must send this token to your backend, where you validate it using the Passage SDK to verify the user's identity and establish an authenticated session.
// On your Node.js backend (e.g., in an Express route)
import { Passage } from '@passageidentity/passage-node';
import express from 'express';
const app = express();
app.use(express.json());
const passage = new Passage({
appId: process.env.PASSAGE_APP_ID,
apiKey: process.env.PASSAGE_API_KEY, // Required for backend SDK operations
});
// An endpoint your frontend calls after successful Passage authentication
app.post('/api/auth/login', async (req, res) => {
try {
// passage.authenticateRequest automatically extracts token from Authorization header
// and verifies it. It returns the Passage User ID if valid.
const userID = await passage.authenticateRequest(req);
if (userID) {
// Token is valid, user is authenticated.
// You can now create a session, set a cookie, or return user-specific data.
console.log(`User ${userID} authenticated successfully.`);
// Example: Set a simple session cookie (for traditional web apps)
// res.cookie('session_id', generateSessionId(userID), { httpOnly: true, secure: true });
res.status(200).json({ status: 'success', userId: userID, message: 'Logged in successfully!' });
} else {
res.status(401).json({ status: 'error', message: 'Invalid Passage token.' });
}
} catch (error) {
console.error('Error during Passage token validation:', error);
res.status(500).json({ status: 'error', message: 'Internal server error during authentication.' });
}
});
C. Managing User Data and Customization (Backend)
Once a user is authenticated, you can retrieve their profile information from Passage using the SDK. This allows you to personalize the user experience or link the Passage user to your application's internal user model. You can also customize user-facing messages or themes.
// On your Node.js backend
import { Passage } from '@passageidentity/passage-node';
// Assume 'passage' is initialized as in previous examples
// Example: Retrieve user details after authentication
app.get('/api/users/me', async (req, res) => {
// Assuming req.passageUserId was set by an authentication middleware
const passageUserId = req.passageUserId; // This comes from a validated Passage token
if (!passageUserId) {
return res.status(401).json({ message: 'User not authenticated.' });
}
try {
// Fetch user data from Passage
const user = await passage.users.get(passageUserId);
if (user) {
// You can now use `user.email`, `user.phone`, `user.user_metadata`, etc.
// Link this to your internal user profile if necessary.
res.status(200).json({
passageId: user.id,
email: user.email,
// Include other relevant Passage user data
userMetadata: user.user_metadata,
// ...
});
} else {
res.status(404
## Anti-Patterns
**Using the service without understanding its pricing model.** Cloud services bill differently — per request, per GB, per seat. Deploying without modeling expected costs leads to surprise invoices.
**Hardcoding configuration instead of using environment variables.** API keys, endpoints, and feature flags change between environments. Hardcoded values break deployments and leak secrets.
**Ignoring the service's rate limits and quotas.** Every external API has throughput limits. Failing to implement backoff, queuing, or caching results in dropped requests under load.
**Treating the service as always available.** External services go down. Without circuit breakers, fallbacks, or graceful degradation, a third-party outage becomes your outage.
**Coupling your architecture to a single provider's API.** Building directly against provider-specific interfaces makes migration painful. Wrap external services in thin adapter layers.
Install this skill directly: skilldb add auth-services-skills
Related Skills
Auth0
Build with Auth0 for enterprise authentication and identity. Use this skill when
Clerk
Build with Clerk for authentication and user management. Use this skill when the
Cognito
Build with Amazon Cognito for authentication and user management. Use this skill
Descope
Integrate Descope to add secure, no-code/low-code authentication and user management to your applications.
Firebase Auth
Build with Firebase Authentication for user sign-in. Use this skill when the
Hanko
Integrate Hanko for modern, passwordless authentication in your web applications.