@passageidentity/passage-elements
TypeScript icon, indicating that this package has built-in type declarations

1.21.4 • Public • Published

Passage logo

npm version

passage-elements

Instantly add authentication to any website with Passage custom elements.

The Passage Elements are the easiest way to use Passage in your web application. An Element is a modular component that provides a complete UI/UX for modern authentication, embedded directly into your website. The Elements work in any modern frontend framework and you can see a guide for your specific framework here.

What's Included?

🙆 User login, registration, and profile cross-platform elements.

🎨 Complete UI/UX for all device types and auth flows – in other words, it just works.

🔒 Full passkey authentication.

✨ Magic Link and One-Time Passcodes over email or SMS.

Getting Started

Install this package using npm.

npm i --save @passageidentity/passage-elements

This package includes five custom elements: passage-auth, passage-login, passage-register, passage-profile, and passage-passkey-table.

  • passage-auth is a single element that handles both login and registration of users.
  • passage-login and passage-register split out the login and register operations into separate elements. These elements should be used when your login and registration functionality are on different pages.
  • passage-profile is an element that allows users to manage their stored profile information. The profile element provides a UI for users to view and edit their account data and perform actions such as updating their email or adding a device to their account.
  • passage-passkey-table is an element that renders a table of passkeys associated with the current user. This table is used within the <passage-profile> element and is often used standalone in situations where you want users to have passkey management but not identifier management capabilities. The table can view, edit, add, and revoke passkeys from the user's account.

Using a Passage Custom Element

Import the custom elements in your JavaScript/TypeScript module:

import '@passageidentity/passage-elements/passage-auth'
import '@passageidentity/passage-elements/passage-login'
import '@passageidentity/passage-elements/passage-register'
import '@passageidentity/passage-elements/passage-profile'
import '@passageidentity/passage-elements/passage-passkey-table'

This import will register just the associated custom elements which can then be used as HTML tags like:

<passage-auth app-id="<PASSAGE_APP_ID"></passage-auth>
<passage-login app-id="<PASSAGE_APP_ID"></passage-login>
<passage-register app-id="<PASSAGE_APP_ID"></passage-register>
<passage-profile app-id="<PASSAGE_APP_ID"></passage-profile>
<passage-passkey-table app-id="<PASSAGE_APP_ID"></passage-passkey-table>

Your <PASSAGE_APP_ID> can be located in the Passage Console. If you don't have an App ID, you can create one in 60 seconds. Create an App →

For example, your login page might have the following structure:

<html>
    <head>
        <title>Login to My Website</title>

        ...

        <script src="https://psg.so/web.js" defer></script>
    </head>
    <body>
        ...

        <passage-auth app-id="<PASSAGE_APP_ID>"></passage-auth>

        ...
    </body>
</html>

Optional Attributes

default-country-code

Used to set the default country when a user enters a phone number.

The value should be a string that represents an ISO country code. If no value is passed it will default to "us".

Typescript Support

PassageElement Type

<passage-auth>, <passage-login>, and <passage-register> all support the same prototype taking an app-id as an attribute, reflected as a property appId, and accepting properties for onSuccess and beforeAuth to set custom callback behavior.

If you are using TypeScript with your project you can import a PassageElement interface to see all available properties and methods on the elements:

import '@passageidentity/passage-elements/passage-auth'
import { PassageElement } from '@passageidentity/passage-elements'

Note: You will still need to import the top level package as a separate import because this is needed to register the custom elements for use in your module.

The PassageElement interface is defined as:

interface PassageElement extends HTMLElement {
  appId?: string
  onSuccess?: OnSuccessCallback
  beforeAuth?: BeforeAuthCallback
  lang: string,
  defaultCountryCode?: string,
  tokenStore?: TokenStore,
}

Using this interface allows you to add additional type safety when interacting with the properties and methods on Passage Elements.

const passageAuth = document.querySelector('passage-auth') as PassageElement
const passageLogin = document.querySelector('passage-login') as PassageElement
const passageRegister = document.querySelector('passage-register') as PassageElement

PassageProfileElement Type

The <passage-profile> and <passage-passkey-table> elements have a similar type to PassageElement called PassageProfileElement. This type shares most of the properties as PassageElement but does not have any callback properties.

The PassageProfileElement type can be imported from the same top-level package entry point:

import { PassageProfileElement } from '@passageidentity/passage-elements'

The full PassageProfileElement interface is defined as:

export interface PassageProfileElement extends HTMLElement {
    appId?: string;
    lang: string;
    defaultCountryCode?: string;
    tokenStore?: TokenStore;
}

PassageUser Class

Use this class to check if a user is authenticated from your frontend app.

After the user has logged in with Passage, you can perform some basic actions on that user from your frontend application. The current functionality available is:

  • Retrieve basic user information.
  • Check if a user is authenticated.
  • Refresh or revoke user sessions.

These functions are accessible from your frontend application using the PassageUser class exported from @passageidentity/passage-elements/passage-user. With an instantiated PassageUser instance, you can create a reusable composable in any frontend framework to manage the current user context in your application.

Constructor

The PassageUser() constructor does not require any arguments. By default, the constructor will create the user class based on the Passage auth token stored in local storage (psg_auth_token), which is populated by the default success callback.

If you are setting the Passage auth token differently, you can pass the token in directly.

import { PassageUser } from '@passageidentity/passage-elements/passage-user';

// default constructor
const user = new PassageUser();

// optionally pass in auth token
const user = new PassageUser(authToken);

Auth Guard

The authGuard() method is used to check if a user is authenticated and returns a boolean indicating if the user's token is valid. This method can be used as an authenticated route guard to check if a user's token is valid.

Note: The authGuard() method can be used as a route guard in your single page application, but it should NOT be used make auth decisions on API routes.

When making requests to your API you must use one of the Passage backend SDKs to safely verify user authentication tokens.

An example of using the Auth Guard in a React application is shown below.

import { useState, useEffect } from "react";
import { PassageUser } from '@passageidentity/passage-elements/passage-user';

export function useAuthStatus() {
  const [result, setResult] = useState({
    isLoading: true,
    isAuthorized: false,
  });

  useEffect(() => {
    let cancelRequest = false;
    new PassageUser().authGuard().then(res => {
      if( cancelRequest ) {
          return;
      }
      if(res === false){
          setResult({
              isLoading: false,
              isAuthorized: false,
            });
            return;
      }
      setResult({
          isLoading: false,
          isAuthorized: true,
        });
    });
    return () => {
      cancelRequest = true;
    };
  }, []);
  return result;
}

User Info

Call the userInfo() method to retrieve the current user's information once they have authenticated.

Example

import { PassageUser } from '@passageidentity/passage-elements/passage-user';

// By default, the current user's authToken will be fetched from localStorage
// and will be used to fetch the current user's information via the
// userInfo() method:

import { PassageUser } from '@passageidentity/passage-elements/passage-user';

//uses current user
const user = new PassageUser()

const userInfo = await user.userInfo()

Example Response

{
    "created_at": "2022-01-19T19:56:44.80799Z",
    "updated_at": "2022-01-21T19:32:16.848273Z",
    "active": true,
    "id": "<userID>",
    "email": "user@passage.id",
    "phone": "",
    "webauthn": false,
    "webauthn_devices": [],
    "last_login_at": "2022-01-21T19:32:16.841947Z",
    "login_count": 3
}

SignOut

Call the signOut() method to delete the users auth token from local storage and revoke their refresh token. The promise will resolve with true if the signOut actions are successful.

Return Value Boolean: the promise will resolve with true if the signOut actions are successful.

Example

import { PassageUser } from '@passageidentity/passage-elements/passage-user';

const user = new PassageUser()

const signedOut = await user.signOut()

GetAuthToken

Call the getAuthToken method to retrieve the auth token of the current user.

If the user has a valid refresh token and an invalid auth token it will silently attempt to refresh the auth token.

Return Value String: the users authToken value.

If no valid auth token or refresh token is found it will thrown an exception for 'Login required'

Example

import { PassageUser } from '@passageidentity/passage-elements/passage-user';

const user = new PassageUser()

const userAuthToken = await user.getAuthToken()

Refresh

Call the refresh method to refresh the auth token of the current user. Refresh tokens must be enabled to use this method.

For most cases we recommend using the getAuthToken method which will silently run the refresh method if the user has an invalid auth token stored.

Return Value String: the users authToken value.

If no valid auth token or refresh token is found it will thrown an exception for 'Login required'

Example

import { PassageUser } from '@passageidentity/passage-elements/passage-user';

const user = new PassageUser()

const userAuthToken = await user.refresh()

Framework Examples

React

Integrate Passage into your React application

To see a full example of using Passage in a React + Express.js application, please visit our sample app on GitHub.

Importing and Using the Passage-Auth Custom Element

The easiest way to add authentication to a web frontend is with a Passage Auth custom element. First you'll need to install the passage-elements package from npm:

npm i --save @passageidentity/passage-elements

Then import the package in the module where you intend to use the custom element

import '@passageidentity/passage-elements/passage-auth';

Importing this script will register the Passage custom element for use in your React components. For more information about custom elements, refer to the online documentation.

It's then just a matter of embedding the <passage-auth> element into your component that will handle login.

<div className={styles.authContainer}>
    <passage-auth app-id={process.env.REACT_APP_PASSAGE_APP_ID}></passage-auth>
</div>

Typescript Support

If you are using TypeScript with your React application, you’ll need to add the following type declaration to your typings.d.ts file:

declare namespace JSX {
    import { PassageElement, PassageProfileElement } from '@passageidentity/passage-elements';
    interface IntrinsicElements {
        'passage-auth': PassageElement;
        'passage-login': PassageElement;
        'passage-register': PassageElement;
        'passage-profile': PassageProfileElement;
        'passage-passkey-table': PassageProfileElement;
    }
}

Getting Authentication Status and User Information

After the user has logged in with Passage, you can check if a user's authentication token is valid and retrieve basic user information from Passage using the PassageUser class exported from @passageidentity/passage-elements/passage-user.

import { PassageUser } from '@passageidentity/passage-elements/passage-user';
...
useEffect(() => {
    let cancelRequest = false;
    new PassageUser().userInfo().then(userInfo=> {
...

Note: The PassageUser().authGuard() function can be used as a route guard in your application, but it should NOT be make authorization decisions when fetching data from an API server. Route guards provide a better user experience, but less security than using one of Passage's backend libraries. For applications using an API server, you must use one of the Passage backend SDKs to safely verify user authentication tokens.

Defining Callbacks

To define a callback on a Passage Element in React, you can attach a ref to the element and then set the callback on that ref in a useEffect(). An example is shown below.

import '@passageidentity/passage-elements/passage-auth';
import { useEffect, useRef } from 'react';

function Home() {
    const ref = useRef();

    const beforeAuth = (email) => {
        console.log(email);
        return true;
    };

    useEffect(() => {
        const { current } = ref;
        current.beforeAuth = beforeAuth;
        return () => {};
    });

    return <passage-auth ref={ref} app-id={process.env.REACT_APP_PASSAGE_APP_ID}></passage-auth>;
}

export default Home;

Learn more about the available callbacks here.

Next.js

Integrate Passage into your Next.js application

To see a full example of using Passage in a Next.js application, please visit our sample app on GitHub.

Next.js is a front-end framework that builds additional functionality on top of React. Next.js by default pre-renders pages server-side to speed up delivering rendered pages and provide better SEO support. When using Passage in pre-rendered pages there are some specific changes to the standard React development workflow that need to be considered.

We have a blog post entitled Building a Next.js App with Biometrics that provides further information on implementing with Next.js.

Importing and Using the Passage-Auth Custom Element

The easiest way to add authentication to a web frontend is with a Passage Auth custom element. First you'll need to install the passage-elements package from npm:

npm i --save @passageidentity/passage-elements

Then import the package in the module where you intend to use the custom element

import '@passageidentity/passage-elements/passage-auth';

Calling the import statement on the Passage npm package triggers a side-effect that will register the custom element with the client browser for usage. Since Next.js pre-renders pages on the server this presents a common issue with using web components, such as the Passage elements, in pre-rendered pages - when the server side pre-render occurs there is no client window defined to call window.customElements.define() on, which results in an error being thrown.

The most common solution when using custom elements in pre-rendered applications is to defer the registration of the custom element to a lifecycle hook so that the code is only executed when the client app is executed in browser.

export default function Home() {
    useEffect(() => {
        require('@passageidentity/passage-elements/passage-auth');
    }, []);

    return <div>...</div>;
}

Typescript Support

If you are using TypeScript with your Next.js application, you’ll need to add the following tfype declaration to your typings.d.ts file:

declare namespace JSX {
    import { PassageElement, PassageProfileElement } from '@passageidentity/passage-elements';
    interface IntrinsicElements {
        'passage-auth': PassageElement;
        'passage-login': PassageElement;
        'passage-register': PassageElement;
        'passage-profile': PassageProfileElement;
    }
}

Getting Authentication Status and User Information with Server-Side Rendering

After the user has logged in with Passage, all requests need to be authenticated using the JWT provided by Passage. Use the Passage Node.js SDK to authenticate requests and retrieve user data for your application.

You can handle authentication securely in Next.js's server-side rendering function getServerSideProps(). Per Next.js documention you can import modules in top-level scope for use in getServerSideProps. Imports used in getServerSideProps will not be bundled for the client-side. This means you can write server-side code directly in getServerSideProps.

The JWT provided by Passage is stored in both cookies and localstorage. Next.js provides the cookies set for an application to getServerSideProps which allows passing the JWT from the client browser to the server to handle authentication.

Note: Handling authentication in a server-side pre-rendered function is not strictly necessary. If you prefer to call an authentication endpoint on your server after the page is delivered to the client you can still do so as you otherwise might in React.

Vue

Integrate Passage into your Vue application

To see a full example of using Passage in a Vue + Express.js application, please visit our sample app on GitHub.

Importing and Using the Passage-Auth Custom Element

The easiest way to add authentication to a web frontend is with a Passage Auth custom element. First you'll need to install the passage-elements package from npm:

npm i --save @passageidentity/passage-elements

Then import the package in the module where you intend to use the custom element

import '@passageidentity/passage-elements/passage-auth';

Importing this script will register the Passage custom element for use in your Vue components. For more information about custom elements refer to the online documentation.

It's then just a matter of embedding the passage-auth element into your component that will handle login.

<div class="authContainer">
  <passage-auth :app-id="appId"></passage-auth>
</div>

Configuring Vue to Recognize Custom Elements

Vue works with custom elements out of the box but by default it will log a warning to the console that it could not resolve the component for the custom element. To configure Vue with information that the tag is a custom element and suppress this warning you can add this configuration to vue.config.js:

compilerOptions: {
  // treat any tag that starts with passage- as custom elements
  isCustomElement: (tag) => tag.startsWith('passage-'),
},

Getting Authentication Status and User Information

After the user has logged in with Passage, you can check if a user's auth token is valid and retrieve basic user information from Passage using the PassageUser class exported from @passageidentity/passage-auth/passage-user.

import { PassageUser } from '@passageidentity/passage-elements/passage-user'

export function useAuthStatus(){
...
  new PassageUser().userInfo().then(userInfo => {
...

Note: The PassageUser().authGuard() can be used as a route guard in your application, but it should NOT be make authorization decisions when fetching data from an API server. Route guards provide a better user experience, but less security than using one of Passage's backend libraries. For applications using an API server, you must use one of the Passage backend SDKs to safely verify user authentication tokens.

Angular

Integrate Passage into your Angular application

To see a full example of using Passage in an Angular + Express.js application, please visit our sample app on GitHub.

Importing and Using the Passage-Auth Custom Element

The easiest way to add authentication to a web frontend is with a Passage Auth custom element. First you'll need to install the passage-elements package from npm:

npm i --save @passageidentity/passage-elements

Then import the package in the module where you intend to use the custom element. In an Angular application this can be done at the application level, as in this example in app.module.ts or in a sub-module that contains the login/registration page.

import '@passageidentity/passage-elements/passage-auth';

Importing this script will register the Passage custom element for use in your Angular components. For more information about custom elements refer to the online documentation.

It's then just a matter of embedding the passage-auth element into your component template that will handle login.

<div class="authContainer">
  <passage-auth [appId]="appId"></passage-auth>
</div>

Configuring Angular to Recognize Custom Elements

For Angular to recognize a non-Angular component tag as a custom element the Angular module that uses the custom element must be configured with the custom element schema.

@NgModule({
  ...
  schemas: [CUSTOM_ELEMENTS_SCHEMA],
  ...
})
export class AppModule { }

Getting Authentication Status and User Information

After the user has logged in with Passage, all requests to your backend need to be authenticated using the JWT provided by Passage. In our example app, we set the JWT in an Authorization header to our API server.

The example project uses a simple Express backend and the Passage Node.js SDK to authenticate requests and retrieve user data for your application. You can see how that runs in the /backend folder of this repository.

The example application handles communication with the backend API in the ngOnInit lifecycle method of frontend/src/views/Dashboard/dashboard.component.ts.

UI Customization

The passage-auth, passage-login, and passage-register elements can be customized in two ways: via Console using the Element Customization settings, or via CSS variables and parts on the host webpage. The passage-profile element can be customized via CSS variables and parts as well.

For more information on Element UI customization and to learn how to customize the look and feel of the Passage Element to match your brand, including available CSS variables and how to use them, refer to Element UI Customization in the Passage Docs.

Note: We do not recommend using both CSS variables and Console to style the elements due to CSS variable heirarchy. For more information, please visit the docs linked above.

Custom Token Store

The passage-auth, passage-login, and passage-register and passage-profile elements can each take an optional tokenStore property, giving you full control over how auth tokens are stored in the client.

For more information on how to create a custom token store, refer to With Token Store in the Passage Docs.

Readme

Keywords

none

Package Sidebar

Install

npm i @passageidentity/passage-elements

Weekly Downloads

177

Version

1.21.4

License

ISC

Unpacked Size

1.87 MB

Total Files

30

Last publish

Collaborators

  • jennmacfarlane
  • passageamy
  • rickypadilla
  • passenger_mac
  • passage-blayne
  • kevinflanagan
  • colehecht
  • apobletts