Passkeys NPM Package
A minimal TypeScript package for passkey management with configurable backend support. Use the default JAW passkey service or self-host your own compatible server.
Installation & Configuration
Basic Setup
import { configurePasskeys, createPasskey, loginWithPasskey } from '@jaw.id/passkeys'
configurePasskeys({
apiKey: 'your-justaname-api-key'
})
configurePasskeys({
serverUrl: 'https://your-passkey-server.com/api/passkeys'
})
Configuration Options
- Default JAW Service: Requires only an
apiKey
- Custom Server: Requires
serverUrl, apiKey is optional
The package validates configuration automatically:
- JustaName service URLs require an API key
- Custom servers don't require an API key
Server Implementation Requirements
Your passkey server must implement the following endpoints and data structures to be compatible:
Endpoints
1. GET / - Lookup Passkeys by Credential IDs
Retrieves passkey information for one or more credential IDs.
Query Parameters:
credentialIds (string[], repeatable): Array of credential IDs to lookup
Response Format:
{
"statusCode": 200,
"result": {
"data": {
"passkeys": [
{
"credentialId": "string",
"publicKey": "0x...",
"displayName": "string"
}
]
},
"error": null
}
}
Note: publicKey must be hex-encoded with 0x prefix.
Error Response (404):
{
"statusCode": 404,
"result": {
"data": null,
"error": "Passkeys not found"
}
}
2. POST / - Register a New Passkey
Registers a new passkey credential.
Request Body:
{
"credentialId": "string",
"publicKey": "0x...",
"displayName": "string"
}
Note: publicKey must be hex-encoded with 0x prefix.
Headers:
Content-Type: application/json
Response:
- Status 200/201 for successful registration
- Status 4xx/5xx for errors
Data Format Requirements
- Public Keys: Must be hex-encoded strings prefixed with
0x
- Credential IDs: Base64url-encoded strings (standard WebAuthn format)
- Display Names: Human-readable names for the passkeys
Security Considerations
When implementing your own passkey server:
- HTTPS Required: Always use HTTPS in production
- Authentication: Implement appropriate authentication if needed (API keys, OAuth, etc.)
- Data Validation: Validate all incoming credential IDs and public keys
- Storage: Securely store passkey data with appropriate encryption
- CORS: Configure CORS headers to allow requests from your application domain
Example Implementation (Node.js/Express)
const express = require('express');
const app = express();
const passkeys = new Map();
app.get('/api/passkeys', (req, res) => {
const credentialIds = req.query.credentialIds || [];
const ids = Array.isArray(credentialIds) ? credentialIds : [credentialIds];
const foundPasskeys = ids
.map(id => passkeys.get(id))
.filter(Boolean);
if (foundPasskeys.length === 0) {
return res.status(404).json({
statusCode: 404,
result: {
data: null,
error: 'Passkeys not found'
}
});
}
res.json({
statusCode: 200,
result: {
data: {
passkeys: foundPasskeys
},
error: null
}
});
});
app.post('/api/passkeys', express.json(), (req, res) => {
const { credentialId, publicKey, displayName } = req.body;
if (!credentialId || !publicKey || !displayName) {
return res.status(400).json({
statusCode: 400,
result: {
data: null,
error: 'Missing required fields'
}
});
}
passkeys.set(credentialId, {
credentialId,
publicKey,
displayName
});
res.status(201).send();
});
app.listen(3000);
API Usage
Creating a Passkey
import { createPasskey } from '@jaw.id/passkeys'
try {
const passkey = await createPasskey('My Passkey')
console.log('Created passkey:', passkey.id)
} catch (error) {
console.error('Failed to create passkey:', error)
}
Login with Passkey
import { loginWithPasskey, loginWithSpecificPasskey } from '@jaw.id/passkeys'
const passkey = await loginWithPasskey()
const specificPasskey = await loginWithSpecificPasskey('credential-id')
Local Storage Management
import {
checkAuth,
storePasskeyAccount,
fetchAccountsFromLocalStorage
} from '@jaw.id/passkeys'
const authResult = await checkAuth()
console.log('Is authenticated:', authResult.isAuthenticated)
const accounts = fetchAccountsFromLocalStorage()
Testing Your Implementation
To verify your server is compatible:
- Configure your server endpoint using
configurePasskeys()
- Test passkey registration through your application
- Test passkey authentication/login
- Verify that multiple credential ID lookups work correctly
Default Service
If no configuration is provided, the package defaults to the JustaName passkey service at https://api.justaname.id/wallet/v2/passkeys. When using the default service, you must provide an API key:
configurePasskeys({
apiKey: 'your-justaname-api-key'
})