npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@trusona/webauthn

v1.6.5

Published

Trusona WebAuthn SDK

Downloads

1,069

Readme

Trusona AuthCloud WebAuthn SDK

.github/workflows/ci-tester.yml latest

Introduction

Tenant Creation

To use this SDK, Trusona must create a tenant within our infrastructure for your domain.

Contact us about that at [email protected]

As part of this step, Trusona shall provide you with access to a portal where you can find your unique tenantId that would be used to initialize the SDK.

JWKS Endpoint

Within your infrastructure, an URL endpoint must be implemented to provide public keys' information in a JWKS format.

You will provide this endpoint to us as part of of tenant configuration via the portal.

Our APIs expect this to be available and will verify the validity of provided tokens against this endpoint.

Any failure of this check, will fail the corresponding SDK call.

SDK Usage

Installation

Install the SDK into your application or library with npm.

npm install @trusona/webauthn

If you use yarn as your package manager, you can install it similarly:

yarn install @trusona/webauthn

Declaration

Add a reference to the library within your implementation.

The provided snippets below are in typescript

import * as trusona from '@trusona/webauthn'

Preflight Checks

It is prudent to perform some preflight checks before you initialize the SDK to ensure your users have a compatible browser.

This can be accomplished with a static check() method that returns an object with various properties indicating the available WebAuthn capabilities that would allow the user to successfully complete enrollment and authentication on their current browser.


const deviceSupport:Preflight = await trusona.DefaultPreflightChecks.check()

if (deviceSupport.webauthn) {
  if(deviceSupport.platformAuthenticator && deviceSupport.conditionalMediation) {
    // browser has a hardware platform authenticator and can complete CUI
    // notes on CUI - https://github.com/w3c/webauthn/wiki/Explainer:-WebAuthn-Conditional-UI
    //
  }
  if(deviceSupport.platformAuthenticator && !deviceSupport.conditionalMediation) {
    // browser has a hardware platform authenticator but does not have CUI support
    //
  }
  if(!deviceSupport.platformAuthenticator && !deviceSupport.conditionalMediation) {
    // browser does *not* have a hardware platform authenticator and does not have CUI support
    //
  }
} else {
  //
  // Current user or browser is not supported. Let them know. 
  //
  // Gently guide them to a better browser :)
  //
}

Initialization

Next, in a constructor or other early first-run logic, initialize the SDK.

This should only be done once.


// not a secret; but is unique to the tenant; contact Trusona for your own value.
const origin:string = 'sdk-webauthn.your-domain.com'

trusona.Initializer.initialize(origin)
  .then((_) => {
    // successfully initialized; your happy path code
  })
  .catch((error) => {
    // failed initialization! Is the tenant ID correct? Your error handling code
  })

Enroll Your Users

Enrollment sequence diagram

To enroll a user, from within your backend, generate a JWT token with the subject claim as a user's identifier or username.

This identifier does not need to be an email address, but it should uniquely identify the user and they should be able to recognize it as their username.

Once generated, invoke the enroll(string) method with the token as the parameter.

const jwt: string = 'jwt.token-with-subject-claim.signature' // generated from your backend
const controller: AbortController = new AbortController()

new trusona.WebAuthnEnrollment().enroll(jwt, controller.signal)
  .then((status) => {
    // your happy path code after enrollment .. the user is now enrolled
  })
  .catch((error) => {
    // your error handling code ... enrollment failed
    // examine the provided error for details
  })

Authenticate Your Users

Authentication sequence diagram

To authenticate a user, you can provide a username hint to the SDK or not - lastUserHint() is available to provide such a hint.

On success, a JWT is going to be provided in the SDK response that you can examine and verify the identity of the user.

The subject claim in the provided JWT will match subject that was provided during enrollment.

const controller: AbortController = new AbortController()
const webAuthnAuthentication = new trusona.WebAuthnAuthentication()
const usernameHint: string = webAuthnAuthentication.lastUserHint() // optional

webAuthnAuthentication.authenticate(controller.signal, usernameHint)
  .then((map) => {
     // JWT from Trusona identifying the authenticated user
     //
    const idToken:string = map.idToken

    // JWT from Trusona that can be used to access protected resources e.g. Passkey Management
    //
    const accessToken:string = map.accessToken


    const jwksEndpoint:string = trusona.Initializer.jwksEndpoint

    //
    // Verify the JWT against the Trusona's JWKS implementation endpoint. You would
    // do this in your backend services.
    //
    // A "subject" claim will have the username of the authenticated user.
    //
  })
  .catch((error) => {
    // your error handling code ... authentication failed examine the provided error for details

    // Importantly, if the JWT cannot be verified, your users should end up here.
  })

Manage A Users' Passkeys

You can manage a user's passkeys with implemented the PasskeyManagement interface.

An instance of a PasskeyManagement is created using the provided JWT access token available from AuthenticationResult

All active credentials can be returned, and they can be individually deleted.

Also, a passkey's recent activity can be queried.

See the summary below.

API Summary


static async DefaultPreflightChecks.supported () => Promise<boolean>

static async Initializer.initialize(tenantId: string) => Promise<void>

// Instance method of WebAuthnEnrollment
//
async enroll: (token: string, abortSignal?: AbortSignal) => Promise<EnrollmentResult>


// Instance methods of WebAuthnAuthentication
//
async authenticate: (abortSignal: AbortSignal, userIdentifier?: string) => Promise<AuthenticationResult>

// if you have a "webauthn" annotated input field you can use CUI
//
// See https://github.com/w3c/webauthn/wiki/Explainer:-WebAuthn-Conditional-UI
//
async cui: (abortSignal: AbortSignal) => Promise<AuthenticationResult>

// Return a "hint" of the last user identifier that successfully enrolled or
// authenticated at this endpoint.
//
// If a value is not available, an empty (blank) string is returned.
//
// This feature is only applicable if `useLocalStorage` is enabled for your
// tenant, which is "on" by default.
//
lastUserHint: () => string

// Instance methods of PasskeyManagement
//
const passkeyManagement = new DefaultPasskeyManagement(authenticationResult.accessToken) 

// Returns an array of all active and unexpired passkeys for the currently authenticated user.
//
async get: () => Promise<Passkey[]>

// Returns a Promise of true indicating that the specified passkey was successfully deleted.
//
async deletePasskey: (id: string) => Promise<boolean>

// If found, returns the specified passkey. Inactive, or expired passkeys cannot be retrieved.
//
async getPasskey: (id: string) => Promise<Passkey>

// Returns the latest passkey activity for the authenticated user. This data is only available for 
// activity since October 2023
//
async latestPasskeyActivity: () => Promise<Map<string, Map<CredentialActivityType, PasskeyActivity>>>

Troubleshooting

If initialization of the SDK fails, verify that you have specified the correct origin.