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 🙏

© 2026 – Pkg Stats / Ryan Hefner

@jack-henry/consumer-tools

v0.0.11

Published

<!-- SPDX-FileCopyrightText: 2025 Jack Henry

Readme

@jack-henry/consumer-tools

A collection of Vite plugins and web components designed to help build consumer-facing oauth applications within the Jack Henry ecosystem.

Overview

This package provides essential tools for developing consumer applications including:

  • Vite Plugins for development and build-time configuration
  • Web Components for consistent UI layouts
  • Authentication utilities for OIDC integration

Features

Vite Plugins

  • Institution Assets Plugin - Loads institution-specific assets and branding
  • Institution Theme Plugin - Applies institution-specific CSS themes and design tokens
  • Consumer Layout Plugin - Provides layout structure and routing configuration for consumer apps
  • Consumer Auth Plugin - Handles OIDC authentication flow and API proxying

Web Components

  • jh-consumer-layout - A layout component that provides consistent structure for consumer applications
  • jh-consumer-nav - Navigation component for consumer apps

Installation

yarn add @jack-henry/consumer-tools

Peer Dependencies

This package requires openid-client as a peer dependency for authentication features:

yarn add openid-client

Usage

Using Individual Plugins

import { defineConfig } from 'vite';
import {
  institutionAssetsPlugin,
  jhThemePlugin,
  consumerLayoutPlugin,
  consumerAuthPlugin,
} from '@jack-henry/consumer-tools/vite-plugins';

export default defineConfig({
  plugins: [
    institutionAssetsPlugin({ institutionId: 'your-institution-id' }),
    jhThemePlugin({ institutionId: 'your-institution-id' }),
    consumerLayoutPlugin({
      rootTagName: 'your-app',
      institutionId: 'your-institution-id',
      routeConfigPath: './src/routing/route-config.ts', // Optional: path to your route configuration
    }),
    consumerAuthPlugin({
      apiBaseUrl: 'https://your-api-base-url.com',
      clientConfig: {
        client_id: 'your-client-id',
        client_secret: 'your-client-secret',
        grant_types: ['authorization_code'],
        response_types: ['code'],
        token_endpoint_auth_method: 'client_secret_post',
        redirect_uris: ['https://localhost:8445/auth/cb'],
      },
      // Optional: customize auth scope
      authScope: 'openid profile email https://api.banno.com/consumer/auth/offline_access',
      // Optional: customize API headers to copy
      apiHeadersToCopy: ['x-request-id'],
    }),
  ],
});

Using the Combined Consumer Config

For convenience, you can use the default export which combines all consumer plugins:

import { defineConfig } from 'vite';
import consumerConfig from '@jack-henry/consumer-tools/vite-plugins';

export default defineConfig({
  plugins: [
    ...consumerConfig({
      rootTagName: 'your-app',
      institutionId: 'your-institution-id',
      routeConfigPath: './src/routing/route-config.ts', // Optional: path to your route configuration
      auth: {
        apiBaseUrl: 'https://your-api-base-url.com',
        clientConfig: {
          client_id: 'your-client-id',
          client_secret: 'your-client-secret',
          grant_types: ['authorization_code'],
          response_types: ['code'],
          token_endpoint_auth_method: 'client_secret_post',
          redirect_uris: ['https://localhost:8445/auth/cb'],
        },
        // Optional: customize auth scope
        authScope: 'openid profile email https://api.banno.com/consumer/auth/offline_access',
        // Optional: customize API headers to copy
        apiHeadersToCopy: ['x-request-id'],
      },
    }),
  ],
});

Handling Sensitive Credentials

Important: Never commit sensitive credentials like client_secret directly in your code. Use environment variables instead:

import { defineConfig, loadEnv } from 'vite';
import consumerConfig from '@jack-henry/consumer-tools/vite-plugins';

export default defineConfig(async ({ mode }) => {
  // Load environment variables (use empty string to load all vars, not just VITE_*)
  const env = loadEnv(mode, process.cwd(), '');

  return {
    plugins: [
      ...consumerConfig({
        rootTagName: 'your-app',
        institutionId: env.INSTITUTION_ID,
        auth: {
          apiBaseUrl: env.API_URL,
          clientConfig: {
            client_id: env.CLIENT_ID,
            client_secret: env.CLIENT_SECRET,
            grant_types: ['authorization_code'],
            response_types: ['code'],
            token_endpoint_auth_method: 'client_secret_post',
            redirect_uris: JSON.parse(env.REDIRECT_URIS),
          },
        },
      }),
    ],
  };
});

Create a .env file in your project root:

INSTITUTION_ID=your-institution-id
CLIENT_ID=your-client-id
CLIENT_SECRET=your-client-secret
API_URL=https://your-api-base-url.com
REDIRECT_URIS=["https://localhost:8445/auth/cb"]

Note: These variables do not use the VITE_ prefix because they are only used in the Vite configuration and are never exposed to client code. Variables with the VITE_ prefix are embedded into your client bundle and should not contain sensitive information.

Make sure to add .env to your .gitignore:

.env
.env.local

Using Web Components

import '@jack-henry/consumer-tools/components/jh-consumer-layout';

// In your HTML or template
<jh-consumer-layout institutionId="your-institution-id">
  <!-- Your app content -->
</jh-consumer-layout>

Contexts Provided by jh-consumer-layout

The jh-consumer-layout component provides three contexts using Lit's context API that child components can consume to access shared application state.

User Context

Access the current user's authentication state and information.

Import:

import { consume } from '@lit/context';
import { userContext, type UserContext } from '@jack-henry/consumer-tools/contexts/user';

Usage in a Lit component:

@consume({ context: userContext, subscribe: true })
@property({ attribute: false })
user: UserContext;

Interface:

interface UserContext {
  user: User | null;  // User object with profile information
  state: 'unauthenticated' | 'authenticated' | 'loading' | 'checking';
}

interface User {
  sub: string;                // User ID (subject)
  given_name: string;         // First name
  family_name: string;        // Last name
  name: string;               // Full name
  email: string;              // Email address
  nickname: string;           // Username/nickname
  picture: string;            // Profile picture URL
  preferred_username: string; // Preferred display name
  // ... additional OAuth user claims
}

States:

  • unauthenticated - User is not logged in
  • loading - Initial authentication check in progress
  • checking - Re-validating authentication status
  • authenticated - User is logged in and validated

Institution Context

Access the current financial institution's configuration and branding.

Import:

import { consume } from '@lit/context';
import { institutionContext, type InstitutionContext } from '@jack-henry/consumer-tools/contexts/institution';

Usage in a Lit component:

@consume({ context: institutionContext, subscribe: true })
@property({ attribute: false })
institution: InstitutionContext;

Interface:

interface InstitutionContext {
  institution: Institution | null;  // Institution configuration
  state: 'initial' | 'loading' | 'ready' | 'error';
}

interface Institution {
  // Branding
  name: string;
  logo: string;
  images: {
    logoUrl: string;
    faviconUrl: string;
    // ... additional branding images
  };

  // Features and abilities
  abilities: {
    billPay: boolean;
    mobileDeposit: boolean;
    cardControls: boolean;
    // ... many more feature flags
  };

  // Links and resources
  links: InstitutionLink[];

  // ... extensive configuration options
}

States:

  • initial - Not yet loaded
  • loading - Fetching institution data
  • ready - Institution data loaded successfully
  • error - Failed to load institution data

Router Context

Access the router instance and route configuration.

Import:

import { consume } from '@lit/context';
import { routerContext, type RouterContext } from '@jack-henry/consumer-tools/contexts/router';

Usage in a Lit component:

@consume({ context: routerContext, subscribe: true })
@property({ attribute: false })
routerContext: RouterContext;

Interface:

interface RouterContext {
  router: Router | null;      // Router instance for programmatic navigation
  config: RouteConfig | null; // Your application's route configuration
}

Usage example:

// Navigate programmatically
this.routerContext.router.go('/dashboard');

// Access route configuration
const routes = this.routerContext.config;

Complete Component Example

Here's a complete example of a component consuming all three contexts:

import { LitElement, html } from 'lit';
import { customElement, property } from 'lit/decorators.js';
import { consume } from '@lit/context';
import { userContext, type UserContext } from '@jack-henry/consumer-tools/contexts/user';
import { institutionContext, type InstitutionContext } from '@jack-henry/consumer-tools/contexts/institution';
import { routerContext, type RouterContext } from '@jack-henry/consumer-tools/contexts/router';

@customElement('my-dashboard')
export class MyDashboard extends LitElement {
  @consume({ context: userContext, subscribe: true })
  @property({ attribute: false })
  user: UserContext;

  @consume({ context: institutionContext, subscribe: true })
  @property({ attribute: false })
  institution: InstitutionContext;

  @consume({ context: routerContext, subscribe: true })
  @property({ attribute: false })
  routerContext: RouterContext;

  render() {
    if (this.user.state !== 'authenticated') {
      return html`<p>Please log in</p>`;
    }

    return html`
      <h1>Welcome, ${this.user.user.given_name}!</h1>
      <p>Banking with ${this.institution.institution?.name}</p>
      <button @click=${() => this.routerContext.router.go('/settings')}>
        Go to Settings
      </button>
    `;
  }
}

Note: router.go is used as an example of programmatic navigation, but that is only here for demonstration purposes. In most cases you should use <a href="/settings"> for navigation to ensure proper accessibility, bookmarking, and expected web behavior.

Consumer Auth Plugin Details

The Consumer Auth Plugin provides OIDC authentication functionality for consumer applications, handling the OAuth flow, token management, and API proxying for Banno consumer APIs.

Configuration Options

apiBaseUrl (required)

The base URL for the API endpoints.

clientConfig (required)

The OIDC client configuration object containing:

  • client_id: Your OIDC client ID
  • client_secret: Your OIDC client secret
  • grant_types: OAuth grant types (typically ['authorization_code'])
  • response_types: OAuth response types (typically ['code'])
  • token_endpoint_auth_method: Authentication method for token endpoint
  • redirect_uris: Array of allowed redirect URIs

authScope (optional)

The OAuth scope to request. Defaults to:

'openid profile email https://api.banno.com/consumer/auth/offline_access https://api.banno.com/consumer/auth/accounts.readonly https://api.banno.com/consumer/auth/conversations.readonly'

apiHeadersToCopy (optional)

Array of HTTP headers to copy from API responses. Defaults to ['x-request-id'].

Endpoints

The plugin sets up the following endpoints:

  • /auth - Initiates the OAuth flow
  • /auth/cb - OAuth callback endpoint
  • /validate - Returns current user information
  • /a/conversations/api/* - Proxies to conversations API with authentication
  • /a/consumer/api/* - Proxies to consumer API with authentication

Authentication Flow

  1. Navigate to /auth to start the OAuth flow
  2. User is redirected to the OAuth provider
  3. After successful authentication, user is redirected back to /auth/cb
  4. The plugin stores the access token and redirects to /
  5. Subsequent API calls are automatically authenticated

⚠️ Development vs Production

This plugin includes in-memory token storage which is NOT suitable for production use. For production applications, implement proper token storage mechanisms (database, secure session storage, etc.).

Consumer Layout Plugin Details

The Consumer Layout Plugin provides layout structure and routing configuration for consumer applications by automatically wrapping your app's root element with the jh-consumer-layout web component.

Configuration Options

rootTagName (required)

The name of your application's root custom element tag. The plugin will automatically wrap this element with jh-consumer-layout.

institutionId (required)

The institution ID that will be passed to both the layout component and your root application element.

routeConfigPath (optional)

Path to a route configuration file that exports routing information for your application. When provided, the plugin will:

  1. Import the route configuration module
  2. Wait for the jh-consumer-layout component to be defined
  3. Automatically set the routeConfig property on the layout component

Route Configuration

If you provide a routeConfigPath, your route configuration file should export a default object with your routing information:

// src/routing/route-config.ts
export default {
  routes: [
    {
      path: '/',
      component: 'home-view',
      title: 'Home',
    },
    {
      path: '/profile',
      component: 'profile-view',
      title: 'Profile',
    },
  ],
};

The route configuration is automatically applied to the jh-consumer-layout component when the page loads, enabling navigation and routing functionality.

HTML Transformation

The plugin performs the following transformations to your HTML:

  1. If your root tag exists: Wraps it with jh-consumer-layout
  2. If no root tag found: Creates both the layout wrapper and your root tag inside the <body>
  3. If route config provided: Injects a module script that loads and applies the routing configuration

Example transformation:

<!-- Before -->
<body>
  <your-app></your-app>
</body>

<!-- After -->
<body>
  <jh-consumer-layout institution-id="your-institution-id">
    <your-app institution-id="your-institution-id"></your-app>
  </jh-consumer-layout>

  <!-- If routeConfigPath is provided -->
  <script type="module">
    import routeConfig from './src/routing/route-config.ts';
    customElements.whenDefined('jh-consumer-layout').then(() => {
      const consumerLayout = document.querySelector('jh-consumer-layout');
      if (consumerLayout) {
        consumerLayout.routeConfig = routeConfig;
      }
    });
  </script>
</body>

Available Exports

Components

  • @jack-henry/consumer-tools/components/* - Individual consumer application web components

Vite Plugins

  • @jack-henry/consumer-tools/vite-plugins - All Vite plugins and configurations

Development

Building

yarn build

Testing

yarn test

Development Mode

yarn dev

Migration

If you're migrating from inline OIDC configuration to the consumer auth plugin, see the Migration Guide for detailed instructions.

License

UNLICENSED

Repository

GitHub - Banno/digital-ux