Backend API Reference
The Passwordless.dev private API is used by your backend to initiate key registrations, verify sign-ins, retrieve keys for end-users, and more.
All requests made to this API require your API private secret in the header for authentication. Requests made to the public API, which are facilitated by methods in the JavaScript client, will instead require your API public key.
/register/token
Request
POST
requests made to the /register/token
endpoint create a registration token for a user, which will be used by your frontend to negotiate creation of a WebAuth credential.
The request body must include at least a userId
and username
for example:
POST https://v4.passwordless.dev/register/token HTTP/1.1
ApiSecret: myapplication:secret:11f8dd7733744f2596f2a28544b5fbc4
Content-Type: application/json
{
"userId": "107fb578-9559-4540-a0e2-f82ad78852f7",
"username": "pjfry@passwordless.dev",
"displayname": "Philip J Fry",
}
const apiUrl = 'https://v4.passwordless.dev';
const payload = {
userId: '107fb578-9559-4540-a0e2-f82ad78852f7', // A WebAuthn User Handle, which should be generated by your application. Max. 64 bytes.
username: 'pjfry@passwordless.dev', // For display purposes, should help a user identify the user account.
displayname: 'Philip J. Fry', // A human-palatable name for the account.
authenticatorType: 'any', // WebAuthn authenticator attachment modality. Can be "any" (default), "platform" which triggers client device-specific options Windows Hello, FaceID, or TouchID, or "cross-platform", which triggers roaming options like security keys.
userVerification: 'preferred', // Whether the relying party requires locally-invoked authorization for the operation. Can be "preferred" (default), "required", or "optional".
aliases: ['pjfry@passwordless.dev'], // An array of user-created identifiers, like emails, which are used to reference a userId.
aliasHashing: true // Whether aliases should be hashed before being stored. Defaults to true.
};
// POST the payload to the Passwordless.dev API using your API private secret.
const { token } = await fetch(apiUrl + '/register', {
method: 'POST',
body: JSON.stringify(payload),
headers: {
'ApiSecret': 'myapplication:secret:11f8dd7733744f2596f2a28544b5fbc4',
'Content-Type': 'application/json'
}
}).then((r) => r.json());
The request body may include additional parameters besides those required, all of which are listed here:
Parameter | Description | Example Value |
---|---|---|
userId | Required. A WebAuthn User Handle, which should be generated by your application. This is used to identify your user (could be a database primary key ID or a guid). Max. 64 bytes. Should not contain PII about the user. | "107fb578-9559-4540-a0e2-f82ad78852f7" |
username | Required. A human-palatable identifier for a user account. It is intended only for display, i.e., aiding the user in determining the difference between user accounts with similar displayNames. Used in Browser UI's and never stored on the server | "pjfry@passwordless.dev" |
displayname | A human-palatable name for the account, which should be chosen by the user. Used in Browser UI's and never stored on the server. | "Philip J Fry" |
attestation | WebAuthn attestation conveyance preference. Only "none" (default) is supported on 'Trial' & 'Pro' plans. While 'Enterprise' can also use "direct" or "indirect" . (learn more) | "none" (default) |
authenticatorType | WebAuthn authenticator attachment modality. Can be "any" (default), "platform" , which triggers client device-specific options Windows Hello, FaceID, or TouchID, or "cross-platform" , which triggers roaming options like security keys. | "any" (default) |
discoverable | If true , creates a client-side Discoverable Credential that allows sign in without needing a username. | true (default) |
userVerification | Allows choosing preference for requiring User Verification (biometrics, pin code etc) when authenticating Can be "preferred" (default), "required" or "discouraged" . | "preferred" |
expiresAt | Timestamp (UTC) when the registration token should expire. By default, current time + 120 seconds. | "3023-08-01T14:43:03Z" |
aliases | A array of aliases for the userId, such as an email or username. Used to initiate a sign-in on the client side with the signinWithAlias() method. An alias must be unique to the userId. Defaults to an empty array [] . | ["pjfry@passwordless.dev"] |
aliasHashing | Whether aliases should be hashed before being stored. Defaults to true . | true |
Response
If successful, the /register/token
endpoint will create a registration token returned as json, for example:
{ "token": "register_wWdDh02ItIvnCKT_02ItIvn..." }
This registration token will will be used by your frontend to negotiate creation of a WebAuth credential.
/signin/verify
Request
POST
requests made to the /signin/verify
endpoint unpack an authentication token, which must be generated by calling a .signinWith*()
method on your frontend (learn more) and included here in the request body, for example:
POST https://v4.passwordless.dev/signin/verify HTTP/1.1
ApiSecret: myapplication:secret:11f8dd7733744f2596f2a28544b5fbc4
Content-Type: application/json
{
"token": "d5vzCkL_GvpS4VYtoT3..."
}
const apiUrl = 'https://v4.passwordless.dev';
// Fetch the authentication token from your frontend.
const payload = { token: req.query.token };
// POST the authentication token to the Passwordless.dev API using your API private secret.
const response = await fetch(apiUrl + '/signin/verify', {
method: 'POST',
body: JSON.stringify(payload),
headers: {
'ApiSecret': 'myapplication:secret:11f8dd7733744f2596f2a28544b5fbc4',
'Content-Type': 'application/json'
}
});
The Passwordless.dev private API will unpack the authentication token to check its legitimacy.
Response
If successful, the /signin/verify
endpoint will return a success response object, for example:
{
"success": true,
"userId": "123",
"timestamp": "3023-08-01T14:43:03Z",
"rpid": "localhost",
"origin": "http://localhost:3000",
"device": "Firefox, Windows 10",
"country": "SE",
"nickname": "My Work Phone",
"expiresAt": "3023-08-01T14:43:03Z",
"tokenId": "TODO",
"type": "passkey_signin" // or passkey_register
}
Use the .success
value (true
or false
) to determine next actions, i.e. whether to complete the sign-in (learn more).
/signin/generate-token
Request
POST
requests made to the /signin/generate-token
endpoint create a manually generated authentication token for a user, side-stepping the regular sign-in flow (i.e. the .signinWith*()
methods). The resulting token can then be verified through the /signin/verify
endpoint and used just like a regular authentication token.
POST https://v4.passwordless.dev/signin/generate-token HTTP/1.1
ApiSecret: myapplication:secret:11f8dd7733744f2596f2a28544b5fbc4
Content-Type: application/json
{
"userId": "123"
}
const apiUrl = 'https://v4.passwordless.dev';
// Generate an authentication token, side-stepping the usual signin process.
const payload = {
userId: '107fb578-9559-4540-a0e2-f82ad78852f7'
};
// POST the user ID to the Passwordless.dev API using your API private secret.
const response = await fetch(apiUrl + '/signin/generate-token', {
method: 'POST',
body: JSON.stringify(payload),
headers: {
'ApiSecret': 'myapplication:secret:11f8dd7733744f2596f2a28544b5fbc4',
'Content-Type': 'application/json'
}
});
Response
If successful, the /signin/generate-token
endpoint will return a response object, for example:
{
"token": "d5vzCkL_GvpS4VYtoT3..."
}
/alias
Request
POST
requests made to the /alias
endpoint add aliases (learn more) to a user, dictated by their userId
, in order to allow sign-in with additional usernames, email addresses, etc.
The request body must include the user's userId
and a complete array of aliases, as pre-existing aliases are overwritten when the POST
request is made, for example:
POST https://v4.passwordless.dev/alias HTTP/1.1
ApiSecret: myapplication:secret:11f8dd7733744f2596f2a28544b5fbc4
Content-Type: application/json
{
"userId": "107fb578-9559-4540-a0e2-f82ad78852f7",
"aliases": [
"pjfry@passwordless.dev",
"benderrules@passwordless.dev"
],
"hashing": true
}
const apiUrl = 'https://v4.passwordless.dev';
// Fetch an array of existing and new aliases for the user.
const payload = {
userId: '107fb578-9559-4540-a0e2-f82ad78852f7',
aliases: ['pjfry@passwordless.dev', 'benderrules@passwordless.dev'],
hashing: true // Whether to hash aliases before stored, defaults to true.
};
// POST the array to the Passwordless.dev API using your API private secret.
await fetch(apiUrl + '/alias', {
method: 'POST',
body: JSON.stringify(payload),
headers: {
'ApiSecret': 'myapplication:secret:11f8dd7733744f2596f2a28544b5fbc4',
'Content-Type': 'application/json'
}
});
TIP
By default, "hashing": true
will be turned on to hash aliases before they're stored. Hashed aliases will not be viewable to you in the admin console.
A few rules to take into consideration when allowing users to create aliases:
- An alias must be unique to the specified
userId
. - An alias must be no more than 250 characters.
- A
userID
may have no more than 10 aliases associated with it.
Response
Alias are never returned in any API responses, and can be hashed to preserve user privacy (see above). If successful, the /alias
endpoint will return an HTTP 200 OK status code.
/credentials/list
Request
GET
requests made to the /credentials/list
endpoint list all registered credentials associated with a user, as dictated by their userId
. The request must include the userId
in question, for example:
GET https://v4.passwordless.dev/credentials/list?userId=107fb578-9559-4540-a0e2-f82ad78852f7 HTTP/1.1
ApiSecret: myapplication:secret:11f8dd7733744f2596f2a28544b5fbc4
const apiUrl = 'https://v4.passwordless.dev';
// Fetch the userId for the user in question.
const payload = {
userId: '107fb578-9559-4540-a0e2-f82ad78852f7'
};
// POST the userId to the Passwordless.dev API using your API private secret.
const credentials = await fetch(apiUrl + '/credentials/list', {
method: 'POST',
body: JSON.stringify(payload),
headers: {
'ApiSecret': 'myapplication:secret:11f8dd7733744f2596f2a28544b5fbc4',
'Content-Type': 'application/json'
}
}).then((r) => r.json());
Response
If successful, the /credentials/list
endpoint will return an array of .json
objects where each object represents a registered credential:
[
{
"descriptor": {
"type": "public-key",
"id": "2mgrJ6LPItfxbnVc2UgFPHowNGKaYBm3Pf4so1bsXSk"
},
"publicKey": "pQECAyYgASFYIPi4M0A+ZFeyOHEC9iMe6dVhFnmOZdgac3MRmfqVpZ0AIlggWZ+l6+5rOGckXAsJ8i+mvPm4YuRQYDTHiJhIauagX4Q=",
"userHandle": "YzhhMzJlNWItNDZkMy00ODA4LWFlMTAtMTZkM2UyNmZmNmY5",
"signatureCounter": 0,
"createdAt": "2023-04-21T13:33:50.0764103",
"aaGuid": "adce0002-35bc-c60a-648b-0b25f1f05503",
"lastUsedAt": "2023-04-21T13:33:50.0764103",
"rpid": "myapp.example.com",
"origin": "https://myapp.example.com",
"country": "US",
"device": "Chrome, Mac OS X 10",
"nickname": "Fred's Macbook Pro 2",
"userId": "c8a32e5b-46d3-4808-ae10-16d3e26ff6f9"
} //, ...
]
Learn more about what these key-value pairs signify.
/credentials/delete
Request
POST
requests made to the /credentials/delete
endpoint delete a specific credential associated with a user, as dictated by a credentialId
. The request must include the credentialId
in question, for example:
POST https://v4.passwordless.dev/credentials/delete HTTP/1.1
ApiSecret: myapplication:secret:11f8dd7733744f2596f2a28544b5fbc4
Content-Type: application/json
{
"credentialId": "qgB2ZetBhi0rIcaQK8_HrLQzXXfwKia46_PNjUC2L_w"
}
Response
If successful, the /credentials/delete
endpoint will return an HTTP 200 OK status code.
Status codes
The API returns HTTP Status codes for each request.
In case you receive an error, you will also receive a JSON serialized summary of the error in the form of problem details. For more information, see the Errors page.
HTTP Code | Message | Status |
---|---|---|
200 | Everything is OK. | ✅ |
201 | Everything is OK but empty. | ✅ |
400 | Bad request. | 🔴 |
401 | You did not identify yourself. | 🔴 |
409 | Conflict (alias is already in use). | 🔴 |
500 | Something went very wrong on our side. | 🔴 |