Hanko Node.js SDK
This package is maintained by Hanko.
Contents
- Hanko Node.js SDK
Introduction
This SDK provides an API client that lets you communicate with the Hanko Authentication API to easily integrate FIDO®-based authentication into your web application written in Node.js.
Documentation
- Hanko Documentation website
- Hanko Authentication API reference
Installation
npm install @teamhanko/hanko-node
Prerequisites
In order to utilize the client provided by the SDK you need an API URL as well as API credentials in the form of an API key ID and an API secret. View our getting started guide in the official documentation on how to obtain these.
Usage
Create a new Hanko API Client
Once you have set up your account, create a HankoClientConfig
with the API URL, the API Key Id and the API secret and
use it to construct a HankoWebAuthnClient
.
const hanko = require("@teamhanko/hanko-node");
const hankoClient = new hanko.HankoWebAuthnClient({
apiUrl: "API_URL",
apiSecret: "API_SECRET",
apiKeyId: "API_KEY_ID",
});
Customizing the client
The SDK uses Axios as the underlying HTTP client. You can provide a custom AxiosRequestConfig when constructing the HankoWebAuthnClient, e.g. if you want to use a proxy:
const hanko = require("@teamhanko/hanko-node");
const hankoClient = new hanko.HankoWebAuthnClient({
apiUrl: "API_URL",
apiSecret: "API_SECRET",
apiKeyId: "API_KEY_ID",
}, {
proxy: {
protocol: 'https',
host: '127.0.0.1',
port: 9000,
auth: {
username: 'mikeymike',
password: 'rapunz3l'
}
},
});
Register a WebAuthn credential
Registration of a WebAuthn credential involves retrieving credential creation options from the Hanko API (initialization), passing these options to the browser's Web Authentication API and lastly sending the WebAuthn response back to the Hanko API for validation (finalization).
For a more complete example of the authentication process, see the implementation guide in the Hanko documentation.
Step 1: Registration initialization
Using defaults
const hanko = require("@teamhanko/hanko-node");
const hankoClient = ...
hankoClient
.initializeRegistration({
user: {
id: "e3be22a7-13cf-4235-a09c-380dfd44ac04",
name: "john.doe@example.com",
displayName: "John Doe"
}
})
.then((response) => {
// handle success
})
.catch((error) => {
// handle error
});
Modifying registration options
You can modify the default credential creation options for registration as follows (e.g. for a resident key cross-platform authenticator with direct attestation):
const hanko = require("@teamhanko/hanko-node");
const hankoClient = ...
hankoClient
.initializeRegistration({
user: {
id: "e3be22a7-13cf-4235-a09c-380dfd44ac04",
name: "john.doe@example.com",
displayName: "John Doe"
},
options: {
authenticatorSelection: {
userVerification: hanko.UserVerificationRequirement.REQUIRED,
authenticatorAttachment: hanko.AuthenticatorAttachment.CROSS_PLATFORM,
requireResidentKey: true
},
attestation: hanko.AttestationConveyancePreference.DIRECT
}
})
.then((response) => {
//handle success
})
.catch((error) => {
// handle error
});
Step 2: Pass Hanko API response to the browser's Web Authentication API
Initialization with the Hanko API returns a response that represent PublicKeyCredentialCreationOptions that must be provided to the WebAuthn Authentication API to create a credential. The WebAuthn Authentication API requires data that looks like JSON but contains binary data, represented as ArrayBuffers, that needs to be encoded. So we can't pass the Hanko API initializationResponse directly as PublicKeyCredentialCreationOptions, but you can use the Hanko WebAuthn Library that wraps the WebAuthn Authentication API and encodes / decodes the data and allows you to easily pass Hanko API responses to the WebAuthn Authentication API and vice versa.
You need to provide the initializeRegistration
response data to the create
function of the
Hanko WebAuthn Library for creating a credential. Send the WebAuthn
API response to your backend to finalize registration.
Step 3: Registration finalization
Pass the Web Authentication API response as returned from the Hanko WebAuthn library's create
function to the
finalizeRegistration
client method. Assuming you use a web-framework like Express which
already parses the forwarded response:
const hanko = require("@teamhanko/hanko-node");
const hankoClient = ...
router.post(`/initialize`, (req, res) => {
const {webAuthnResponse} = req.body;
hankoClient
.finalizeRegistration(webAuthnResponse)
.then((response) => {
// handle success
})
.catch((error) => {
// handle error
});
...
});
Authenticate with a registered WebAuthn credential
Step 1: Authentication initialization
Using defaults
const hanko = require("@teamhanko/hanko-node");
const hankoClient = ...
hankoClient
.initializeAuthentication({
user: {
id: "e3be22a7-13cf-4235-a09c-380dfd44ac04" // previously retrieved from your user store
}
})
.then((response) => {
// handle success
})
.catch((error) => {
// handle error
});
Modifying authentication options
You can provide options for authentication as follows (e.g. for a non-resident key cross-platform authenticator with required user verification):
const hanko = require("@teamhanko/hanko-node");
const hankoClient = ...
hankoClient
.initializeAuthentication({
user: {
id: "e3be22a7-13cf-4235-a09c-380dfd44ac04" // previously retrieved from your user store
},
options : {
userVerification: hanko.UserVerificationRequirement.REQUIRED,
authenticatorAttachment: hanko.AuthenticatorAttachment.CROSS_PLATFORM,
}
})
.then((response) => {
// handle success
})
.catch((error) => {
// handle error
});
Step 2: Pass Hanko API response to Web Authentication API
You can provide the initializeAuthentication
response data to the get
function of the
Hanko WebAuthn Library to retrieve an assertion from the WebAutnn API.
Step 3: Authentication finalization
Pass the Web Authentication API response as returned from the Hanko WebAuthn Library's get
function to the
finalizeAuthentication
client method.
const hanko = require("@teamhanko/hanko-node");
const hankoClient = ...
router.post(`/finalize`, (req, res) => {
const {webAuthnResponse} = req.body;
hankoClient
.finalizeAuthentication(webAuthnResponse)
.then((response) => {
// handle success
})
.catch((error) => {
// handle error
});
...
});
Making transactions
A transaction is technically the equivalent of an authentication, with the difference being that when initializing a
transaction, a transactionText
can be included, which becomes part of the authentication challenge. This way it will
be cryptographically signed and cannot be altered anymore.
The message itself can be any type of text, so you could sign a JSON object for example. In the following example we
simply use the string Pay 5$ to Bob?
.
Again, this is a 3-step process:
Step 1: Transaction initialization
const hanko = require("@teamhanko/hanko-node");
const hankoClient = ...
hankoClient
.initializeTransaction({
transaction: "Pay 5$ to Bob?",
user: {
id: "e3be22a7-13cf-4235-a09c-380dfd44ac04" // previously retrieved from your user store
}
})
.then((response) => {
// handle success
})
.catch((error) => {
// handle error
});
Step 2: Pass Hanko API response to Web Authentication API
You can provide the initializationResponse
to the get
function of the
Hanko WebAuthn Library for authenticating with a credential.
Step 3: Transaction finalization
Pass the Web Authentication API response as returned from the Hanko WebAuthn Library's get
function to the finalizeTransaction
client method.
const hanko = require("@teamhanko/hanko-node");
const hankoClient = ...
router.post(`/finalize`, (req, res) => {
const {webAuthnResponse} = req.body;
hankoClient
.finalizeTransaction(webAuthnResponse)
.then((response) => {
// handle success
})
.catch((error) => {
// handle error
});
...
});
Credential management
You can list and manage all stored credentials via the Hanko Authentication API.
Listing credentials
To get all credentials for a given user ID:
const hanko = require("@teamhanko/hanko-node");
const hankoClient = ...
hankoClient
.listCredentials({
user_id: "e3be22a7-13cf-4235-a09c-380dfd44ac04", // filter by user id ...
page: 1, // ... page ...
page_size: 10 // ... and page size
})
.then((response) => {
// handle success
})
.catch((error) => {
// handle error
});
You can also retrieve a single credential:
const hanko = require("@teamhanko/hanko-node");
const hankoClient = ...
const credentialId = "AQohBypyLBrx8R_UO0cWQuu7hhRGv7bPRRGtbQLrjl...";
hankoClient
.getCredential(credentialId)
.then((response) => {
// handle success
})
.catch((error) => {
// handle error
});
Updating a credential
You can update the name of a credential:
const hanko = require("@teamhanko/hanko-node");
const hankoClient = ...
const credentialId = "AQohBypyLBrx8R_UO0cWQuu7hhRGv7bPRRGtbQLrjl..."
hankoClient
.updateCredential(credentialId, {
name: "New name for the credential"
})
.then((response) => {
// handle success
})
.catch((error) => {
// handle error
});
Deleting a credential
const hanko = require("@teamhanko/hanko-node");
const hankoClient = ...
const credentialId = "AQohBypyLBrx8R_UO0cWQuu7hhRGv7bPRRGtbQLrjl..."
hankoClient
.deleteCredential(credentialId)
.then((response) => {
// handle success
})
.catch((error) => {
// handle error
});