Please note that LoginID authentication currently supports the platform authenticators (device built-in) which allow the user to authenticate using their biometrics. We are currently working to finalize our support for the roaming authenticators (security keys).
This DirectWeb Developer’s Quickstart Guide serves as an integration guide for our trusted partners so that you will be able to evaluate, test, and launch LoginID’s authentication service using our DirectWeb API.
The DirectWeb API is made available to your web application via the LoginID JavaScript SDK. In contrast to the OpenID Connect flow, the DirectWeb API allows you to leverage LoginID’s authentication capabilities while allowing the user experience to remain completely within your domain.
When the user desires to register or login, your web application should call LoginID’s JavaScript SDK as described below in the document. This allows the SDK to take over the flow from the client-side, without forcing you to manage the nuances of security when interacting with LoginID’s backend.
Depending on the type of authentication requested (e.g. FIDO2, OTP, Password), you maybe able to specify callback functions to manage very specific aspects of the flow via the options field. However, this capability is not available for all authentication types as the flow may not be conducive to such customized experiences.
Our current version of DirectWeb SDK supports only FIDO2 Authentication type.
For example, if the authentication type is FIDO2, the native browser experience as defined by the browser vendor, will drive the experience regarding how the biometrics are requested. On the other hand, if the required authentication is OTP based, you may have an option to specify the UX widget that will receive the OTP from the user.
In order for the LoginID JavaScript SDK to manage the DirectWeb functionality on your behalf, it needs to be configured with your credentials, which you can obtain from LoginID’s dashboard.
To obtain the API key you will need to perform the following steps:
Navigate to https://usw1.loginid.io/en/register and select the “Register a new account” option and follow the instructions to create a new account on LoginID’s dashboard.
Use the navigation bar to select “Integration” and choose Direct Web type.
In the resulting form, you must enter the following information:
App Name
Website URL
Please note that unlike in the OpenID Connect flow, the Website URL is not a callback URL, but the top-level domain that is integrating the DirectWeb API functionality. LoginID’s backend will essentially whitelist this domain against your client profile as an allowable domain to issue cross-origin requests via the DirectWeb API.
Moreover, a callback URL is not needed as with the OpenID Connect integration, since the user experience never leaves your domain when using the DirectWeb API. Therefore, returning back to your domain via a callback URL is not required.
If the Website URL is not specified correctly, the DirectWeb API functionality will fail.
Once you create a new integration you will be provided with the following on our dashboard:
The API key is used to configure LoginID’s JavaScript SDK from your web application
Base URL which provides our SDK which LoginID environment the integration will be using
SDK Script is CDN hosted script you will be used to integrate with our backend
Once the SDK request is submitted (for example via a login or registration by the end user), you will receive an API key and a JWT verification public key. The JWT verification public key can be used to verify the JWT object that is returned by the DirectWeb API once the user registration/login is complete.
While you should generally store the API Key securely (i.e. don’t post it on the internet!), it is not strictly treated as confidential information since any motivated attacker can inspect your web application in their own browser and ascertain the API Key that is used to configure LoginID’s JavaScript SDK. However, this API Key is not very useful for such an attacker since the API key is tightly coupled to the Registered URL that you defined previously, such that it is not practical for the attacker to use the API key on their own web application hosted under a different domain.
Moreover, using the API Key on the attacker’s own customized browser to spoof the origin URL can be mitigated and can be further discussed as necessary.
For the first iteration of the DirectWeb API, the result of the authentication will be returned to the frontend web application directly, where the returned JWT may be verified using the JWT verification public key on your backend for additional assurance. Therefore, a shared secret to facilitate direct backend-to-backend communication (or asymmetric equivalent) is not necessary, but for additional security enhancements in the future, maybe provided with a subsequent version of the DirectWeb API.
The next step is to integrate the LoginID JavaScript SDK to the web application and this can be achieved by copying the SDK script on Step 1 into a .js
file.
You can download the LoginID JavaScript SDK files from the following URLs:
After downloading the SDK file, save it to your vendor/project folder.
Next, the SDK must be initialized with the base URL and API key that were obtained from LoginID’s dashboard in Step 1.
<!-- Import directweb module from LoginID JS SDK --><script src="./src/vendor/loginid.directweb.min.js"></script><script>/*** Given a base URL and an API key, return a DirectWeb object that* allows the registration and authentication operation.** DirectWeb constructor takes the following parameters:* baseURL:String the base URL where the credentials were created* apiKey:String the API key created at LoginID dashboard*/const dw = new LoginID.directweb.default("https://directweb.usw1.loginid.io", "fLari955o86zbedHVT...lcRKoZMoIQ==");// ...</script>
// Import directweb module from LoginID JS SDKimport DirectWeb from "/src/vendor/loginid.directweb.min";/*** Given a base URL and an API key, return a DirectWeb object that* allows the registration and authentication operation.** DirectWeb constructor takes the following parameters:* baseURL:String the base URL where the credentials were created* apiKey:String the API key created at LoginID dashboard*/const dw = new DirectWeb("https://directweb.usw1.loginid.io", "fLari955o86zbedHVT...lcRKoZMoIQ==");// ...
To check FIDO compatibility for your user, call the following method:
<!-- Import browser module from LoginID JS SDK --><script src="./src/vendor/loginid.browser.min.js"></script><script>/*** Method to check for browser Fido2 support, returns true or false.*/const isFido2Supported = await LoginID.browser.default.isFido2Supported();// ...</script>
// Import browser module from LoginID JS SDKimport Browser from "/src/vendor/loginid.browser.min";/*** Method to check for browser Fido2 support, returns true or false.*/const isFido2Supported = await Browser.isFido2Supported();// ...
The code snippet for requesting registration of a new credential for the given username is shown below.
<!-- Import directweb module from LoginID JS SDK --><script src="./src/vendor/loginid.directweb.min.js"></script><script>// ... SDK configuration .../*** Given a username, return a register object with username,* namespace and JWT.** Register method takes the following parameter:* username:String the username provided by the user*/try {const result = await dw.register("john.doe");} catch(e) {// Exception/Error handling}</script>
// Import directweb module from LoginID JS SDKimport DirectWeb from "/src/vendor/loginid.directweb.min";// ... SDK configuration .../*** Given a username, return a register object with username,* namespace and JWT.** Register method takes the following parameter:* username:String the username provided by the user*/try {const result = await dw.register("john.doe");} catch(e) {// Exception/Error handling}
The username is a mandatory field that must be passed into the register function.
The result of the register method returns the following relevant parameters:
Element | Type | Description |
username | string | The username provided during the registration process |
namespace | string | Unique ID of your organization |
jwt | string | The JWT verification public key can be used to verify the JWT object that is returned by the DirectWeb API once the user registration/login is complete. |
The following exceptions can happen during the registration process:
Code | Description |
client_not_found | Client not found for the provided client id |
client_deactivated | Client was deactivated at LoginID dashboard |
username_empty | Username was not provided |
username_taken | Username was already taken for someone else |
username_invalid | Username must have 3 to 128 characters, must start and end with an alphanumerical character, can only have the following special characters but not two in a row: |
If backend assurance is required regarding the result, you can verify the JWT value with the JWT verification public key which can be obtained at the linked below:
curl https://jwt.usw1.loginid.io/certs?kid=<key id here>
where the kid is obtained from the JWT header:
{"alg": "ES256","typ": "JWT","kid": "f82151ed-cdc4-447c-bb80-981bfbcc2497"}
The JWT includes the username, credential type, nonce, timestamp, etc. signed by the LoginID private key that will correspond to the JWT verification public key.
The code snippet to requesting login with an existing credential is shown below.
<!-- Import directweb module from LoginID JS SDK --><script src="./src/vendor/loginid.directweb.min.js"></script><script>// ... SDK configuration .../*** Given a username, return a login object with username,* namespace and JWT.** Login method takes the following parameter:* username:String the username provided by the user*/try {const result = await dw.login("john.doe");} catch(e) {// Exception/Error handling}</script>
// Import directweb module from LoginID JS SDKimport DirectWeb from "/src/vendor/loginid.directweb.min";// ... SDK configuration .../*** Given a username, return a login object with username,* namespace and JWT.** Login method takes the following parameter:* username:String the username provided by the user*/try {const result = await dw.login("john.doe");} catch(e) {// Exception/Error handling}
The result of the register method returns the following relevant parameters:
Element | Type | Description |
username | string | The username provided during the registration process |
namespace | string | Unique ID of your organization |
jwt | string | The JWT verification public key can be used to verify the JWT object that is returned by the DirectWeb API once the user registration/login is complete. |
The discussion above in Step 4 regarding the parameters to and return an object from the register function is equally applicable to the login function here.
The following exceptions can happen during the login process:
Code | Description |
client_not_found | Client not found for the provided client id |
client_deactivated | Client was deactivated via LoginID dashboard |
username_empty | Username was not provided |
username_invalid | Username must have 3 to 128 characters, must start and end with an alphanumerical character, can only have the following special characters but not two in a row: |
user_not_found | User was not found for the username/API key provided |
account_deactivated | Account was deactivated at LoginID dashboard |
account_blocked | Account was blocked as a result of (3 or more - default) failed authentication attempts |
Through this feature, users on a new device will be able to authenticate using their previously registered device.
Currently, the Push Authentication is enabled for users who previously registered with a DirectWeb integration and are trying to authenticate on a different device on a DirectWeb integration. The future iteration of this feature will expand to include other usecases where the user is previously registered via native and OIDC integrations.
This flow enables the new device to request authorization from the pre-registered device.
<!-- Import directweb module from LoginID JS SDK --><script src="./src/vendor/loginid.directweb.min.js"></script><script>// ... SDK configuration .../*** The callback method for the push authentication has the following signature:* code:string A six digit code promoted to the user that can be used* as a fallback option on the pre-registered device* devices:Array An array with device level information* to enable user authorization (ex: OS, browser)* notification:Object An object for the notification methods used for the* push authentication. This can be via email or in-app* push notification.* expireAt:Number The expiration timestamp of the current session* (Unix timestamp in seconds)*/const callback = function (code, devices, notification, expireAt) {// code - e.g. "123456"// devices - e.g. [{os: "Windows", browser: "Chrome"}, ...]// notification - e.g. { email: true, push: false }// expireAt - e.g. 1610050000000}/*** Optional parameters that can be provided for the push authentication method:* transient_email:string the email associated with the user which can* be provided to LoginID and is only used for* communication purposes and not stored on* LoginID system.*/const options = {transient_email: "john.doe@acme.com"}/*** Given a username and a callback method, return a registered* object with username, namespace and JWT.** Push authentication method takes the following parameter:* username:String the username provided by the user* callback:Function the callback provides information about* the authentication process* options:Object optional parameters for the push authentication method*/try {const result = await dw.pushAuthentication("john.doe", callback, options);} catch(e) {// Exception/Error handling}</script>
import DirectWeb from "/src/vendor/loginid.directweb.min";// ... SDK configuration .../*** The callback method for the push authentication has the following signature:* code:string A six digit code promoted to the user that can be used* as a fallback option on the pre-registered device* devices:Array An array with device level information* to enable user authorization (ex: OS, browser)* notification:Object An object for the notification methods used for the* push authentication. This can be via email or in-app* push notification.* expireAt:Number The expiration timestamp of the current session* (Unix timestamp in seconds)*/const callback = (code, devices, notification, expireAt) => {// code - e.g. "123456"// devices - e.g. [{os: "Windows", browser: "Chrome"}, ...]// notification - e.g. { email: true, push: false }// expireAt - e.g. 1610050000000}/*** The optional parameters that can be provided for the* push authentication method:* transient_email:string the email associated with the user which can* be provided to LoginID and is only used for* communication purposes and not stored on* LoginID system.*/const options = {transient_email: "john.doe@acme.com"}/*** Given a username and a callback method, return a registered* object with username, namespace and JWT.** Push authentication method takes the following parameter:* username:String the username provided by the user* callback:Function the callback provides information about* the authentication process*/try {const result = await dw.pushAuthentication("john.doe", callback, options);} catch(e) {// Exception/Error handling}
The username is a mandatory field that must be passed into the pushAuthentication
function. The callback (your application URI that the user will be redirected to and where you will process the response from our servers) must also be passed into the function.
The callback function for the push authentication method takes the following arguments:
Argument | Type | Description |
code | string | A six-digit code promoted to the user that can be used as a fallback option on the pre-registered device |
devices | Array | An array with device-level information to enable user authorization (ex: OS, browser) |
notification | Object | An object for the notification methods used for the push authentication. This can be via email or in-app push notification. |
expireAt | Number | The expiration timestamp of the current session (Unix timestamp in seconds) |
Optional parameters that can be provided for the push authentication method:
Parameter | Type | Description |
transient_email | string | The email associated with the user which can be provided to LoginID and is only used for communication purposes and not stored on LoginID system. |
The result of the pushAuthentication
method returns the following relevant parameters:
Element | Type | Description |
username | string | The username provided during the registration process |
namespace | string | Unique ID of your organization |
The following exceptions can happen during the push authentication process:
Code | Description |
client_not_found | Client not found for the provided client id |
client_deactivated | Client was deactivated via LoginID dashboard |
username_empty | Username was not provided |
username_invalid | Username must have 3 to 128 characters, must start and end with an alphanumerical character, can only have the following special characters but not two in a row: |
user_not_found | User not found for the username/API key provided |
account_deactivated | Account was deactivated via LoginID dashboard |
account_blocked | Account was blocked because of (3 or more - default) failed authentication attempts |
remote_session_in_progress | Each user can have only one active remote session at the time |
remote_session_timeout | The remote session did not happen within the allowed authentication window
(2 mins default) for the active |
This flow enables the pre-registered device to authorize the authentication on the new device.
<!-- Import directweb module from LoginID JS SDK --><script src="./src/vendor/loginid.directweb.min.js"></script><script>// ... SDK configuration .../*** Optional parameters that can be provided for the login method to grant* authorization for the push authentication flow:* remote_session:Object the remote session object takes two optional* parameters, code and session id. The code parameter* is a six digits string that is provided for the user* only on the requesting authorization device. The* session id parameter is a UUID that can be obtained* via the email notification channel. Both parameters* can be used for granting authorization.*/const options = {remote_session: {code: "123456",session_id: "3883c7f2-4e2b-4373-9211-ef99962b6220"}}/*** Given a username and a callback method, return a registered* object with username and namespace.** Push authentication method takes the following parameter:* username:String the username provided by the user* options:Object optional parameters for the login method*/try {const result = await dw.login("john.doe", options);} catch(e) {// Exception/Error handling}</script>
import DirectWeb from "/src/vendor/loginid.directweb.min";// ... SDK configuration .../*** Optional parameters that can be provided for the login method to grant* authorization for the push authentication flow:* remote_session:Object the remote session object takes two optional* parameters, code and session id. The code parameter* is a six digits string that is provided for the user* only on the requesting authorization device. The* session id parameter is a UUID that can be obtained* via the email notification channel. Both parameters* can be used for granting authorization.*/const options = {remote_session: {code: "123456",session_id: "3883c7f2-4e2b-4373-9211-ef99962b6220"}}/*** Given a username and a callback method, return a registered* object with username and namespace.** Push authentication method takes the following parameter:* username:String the username provided by the user* options:Object optional parameters for the login method*/try {const result = await dw.login("john.doe", options);} catch(e) {// Exception/Error handling}
The remote session object takes two optional parameters that can be used for granting authorization.
Argument | Type | Description |
code | String | 6 digit string that is provided for the user only on the requesting authorization device. |
session_id | UUID | Can be obtained from the email notification channel. |
The result of the login method returns the following relevant parameters:
Element | Type | Description |
username | string | The username provided during the registration process |
namespace | string | Unique ID of your organization |
jwt | string | The JWT verification public key can be used to verify the JWT object that is returned by the DirectWeb API once the user registration/login is complete. |
The following exceptions can happen during the push authentication process:
Code | Description |
client_not_found | Client not found for the provided client id |
client_deactivated | Client was deactivated via LoginID dashboard |
username_empty | Username was not provided |
username_invalid | Username must have 3 to 128 characters, must start and end with an alphanumerical character, can only have the following special characters but not two in a row: |
user_not_found | User not found for the username/API key provided |
account_deactivated | Account was deactivated at LoginID dashboard |
account_blocked | Account was blocked after (3 or more - default) failed authentication attempts |
remote_session_not_found | Remote session not found for the provided |
remote_session_maximum_retry_attempts | Remote session authentication failed (3 or more -default) times |
Through this feature, users on a new device will be able to register the device as a new authenticator.
Currently, the Add Authentication is enabled for users who previously registered with a DirectWeb integration and are trying to authenticate on a different device on a DirectWeb integration. The future iteration of this feature will expand to include other usecases where the user is previously registered via native and OIDC integrations.
This flow enables the new device to request authorization from the pre-registered device.
<!-- Import directweb module from LoginID JS SDK --><script src="./src/vendor/loginid.directweb.min.js"></script><script>// ... SDK configuration .../*** The callback method for the add authenticator has the following signature:* code:string A six digit code promoted to the user that can be used* as a fallback option on the pre-registered device* devices:Array An array with device level information* to enable user authorization (ex: OS, browser)* notification:Object An object for the notification methods used for the* add authentictor. This can be via email or in-app* push notification.* expireAt:Number The expiration timestamp of the current session* (Unix timestamp in seconds)*/const callback = function (code, devices, notification, expireAt) {// code - e.g. "123456"// devices - e.g. [{os: "Windows", browser: "Chrome"}, ...]// notification - e.g. { email: true, push: false }// expireAt - e.g. 1610050000000}/*** Optional parameters that can be provided for the add authenticator method:* transient_email:string the email associated with the user which can* be provided to LoginID and is only used for* communication purposes and not stored on* LoginID system.*/const options = {transient_email: "john.doe@acme.com"}/*** Given a username and a callback method, return a registered* object with username, namespace and JWT.** Add authenticator method takes the following parameter:* username:String the username provided by the user* callback:Function the callback provides information about* the authentication process* options:Object optional parameters for the add authenticator method*/try {const result = await dw.addAuthenticator("john.doe", callback, options);} catch(e) {// Exception/Error handling}</script>
import DirectWeb from "/src/vendor/loginid.directweb.min";// ... SDK configuration .../*** The callback method for the add authenticator has the following signature:* code:string A six digit code promoted to the user that can be used* as a fallback option on the pre-registered device* devices:Array An array with device level information* to enable user authorization (ex: OS, browser)* notification:Object An object for the notification methods used for the* add authenticator. This can be via email or in-app* push notification.* expireAt:Number The expiration timestamp of the current session* (Unix timestamp in seconds)*/const callback = (code, devices, notification, expireAt) => {// code - e.g. "123456"// devices - e.g. [{os: "Windows", browser: "Chrome"}, ...]// notification - e.g. { email: true, push: false }// expireAt - e.g. 1610050000000}/*** The optional parameters that can be provided for the* add authenticator method:* transient_email:string the email associated with the user which can* be provided to LoginID and is only used for* communication purposes and not stored on* LoginID system.*/const options = {transient_email: "john.doe@acme.com"}/*** Given a username and a callback method, return a registered* object with username, namespace and JWT.** Add authenticator method takes the following parameter:* username:String the username provided by the user* callback:Function the callback provides information about* the authentication process*/try {const result = await dw.addAuthenticator("john.doe", callback, options);} catch(e) {// Exception/Error handling}
The username is a mandatory field that must be passed into theAddAuthenticator
function. The callback (your application URI that the user will be redirected to and where you will process the response from our servers) must also be passed into the function.
The callback function for the add authenticator method takes the following arguments:
Argument | Type | Description |
code | string | A six digit code promoted to the user that can be used as a fallback option on the pre-registered device |
devices | Array | An array with device-level information to enable user authorization (ex: OS, browser) |
notification | Object | An object for the notification methods used for the add authenticator. This can be via email or in-app push notification. |
expireAt | Number | The expiration timestamp of the current session (Unix timestamp in seconds) |
Optional parameters that can be provided for the add authenticator method:
Parameter | Type | Description |
transient_email | string | The email associated with the user can be provided to LoginID and is only used for communication purposes and not stored on LoginID system. |
The result of the AddAuthenticator
method returns the following relevant parameters:
Element | Type | Description |
username | string | The username provided during the registration process |
namespace | string | Unique ID of your organization |
The following exceptions can happen during the add authenticator process:
Code | Description |
client_not_found | Client not found for the provided client id |
client_deactivated | Client was deactivated via LoginID dashboard |
username_empty | Username was not provided |
username_invalid | Username must have 3 to 128 characters, must start and end with an alphanumerical character, can only have the following special characters but not two in a row: |
user_not_found | User not found for the username/API key provided |
account_deactivated | Account was deactivated at LoginID dashboard |
account_blocked | Account was blocked because of (3 or more - default) failed authentication attempts |
remote_session_in_progress | Each user can have only one active remote session at the time |
remote_session_timeout | The remote session didn't happen within the allowed authentication window (2 min - default) for the active |
This flow enables the pre-registered device to authorize the authentication on the new device.
<!-- Import directweb module from LoginID JS SDK --><script src="./src/vendor/loginid.directweb.min.js"></script><script>// ... SDK configuration .../*** Optional parameters that can be provided for the login method to grant* authorization for the add authenticator flow:* remote_session:Object the remote session object takes two optional* parameters, code and session id. The code parameter* is a six digits string that is provided for the user* only on the requesting authorization device. The* session id parameter is a UUID that can be obtained* via the email notification channel. Both parameters* can be used for granting authorization.*/const options = {remote_session: {code: "123456",session_id: "3883c7f2-4e2b-4373-9211-ef99962b6220"}}/*** Given a username and a callback method, return a registered* object with username and namespace.** Add authenticator method takes the following parameter:* username:String the username provided by the user* options:Object optional parameters for the login method*/try {const result = await dw.login("john.doe", options);} catch(e) {// Exception/Error handling}</script>
import DirectWeb from "/src/vendor/loginid.directweb.min";// ... SDK configuration .../*** Optional parameters that can be provided for the login method to grant* authorization for the add authenticator flow:* remote_session:Object the remote session object takes two optional* parameters, code and session id. The code parameter* is a six digits string that is provided for the user* only on the requesting authorization device. The* session id parameter is a UUID that can be obtained* via the email notification channel. Both parameters* can be used for granting authorization.*/const options = {remote_session: {code: "123456",session_id: "3883c7f2-4e2b-4373-9211-ef99962b6220"}}/*** Given a username and a callback method, return a registered* object with username and namespace.** Add authenticator method takes the following parameter:* username:String the username provided by the user* options:Object optional parameters for the login method*/try {const result = await dw.login("john.doe", options);} catch(e) {// Exception/Error handling}
The remote session object takes two optional parameters that can be used for granting authorization.
Argument | Type | Description |
code | String | 6 digit string that is provided for the user only on the requesting authorization device. |
session_id | UUID | Can be obtained from the email notification channel |
The result of the login method returns the following relevant parameters:
Element | Type | Description |
username | string | The username provided during the registration process |
namespace | string | Unique ID of your organization |
jwt | string | The JWT verification public key can be used to verify the JWT object that is returned by the DirectWeb API once the user registration/login is complete. |
The following exceptions can happen during the add authenticator process:
Code | Description |
client_not_found | Client not found for the provided client id |
client_deactivated | Client was deactivated via LoginID dashboard |
username_empty | Username was not provided |
username_invalid | Username must have 3 to 128 characters, must start and end with an alphanumerical character, can only have the following special characters but not two in a row: |
user_not_found | User not found for the username/API key provided |
account_deactivated | Account was deactivated via LoginID dashboard |
account_blocked | Account was blocked after (3 or more - default) failed authentication attempts |
remote_session_not_found | Remote session not found for the provided |
remote_session_maximum_retry_attempts | Remote session authentication failed (3 or more -default) times |
We’re happy to assist, if you have any questions please don’t hesitate to contact dev@loginid.io.
Do you have any specific requests for the examples using other frameworks or programming languages? Contact us and let’s talk about bringing secure, private authentication to your application, we have engineers on standby to discuss.