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

oidc-connector

v1.4.5

Published

oidc client connector

Downloads

190

Readme

Build Status npm version Downloads per month

oidc-connector

  • OpenID Connect connector/ client for modern browsers.
  • Configuration uses ./well-known/oidc-configuration provided by OIDC servers.
  • Extensive test-set
  • Easy configuration
  • Event based API

Features

  • Minified ~22kB in size
  • No external dependencies
  • Supports standard, hybrid and implicit authentication flow.
  • Native Promise based
  • Session management
  • Optional PKCE authorization flow
  • Silent login
  • Tokens are refreshed automatically; No need to take care on expiry timestamps.
  • Support for custom adapters (default is browser, package comes bundled with cordova and cordova-native adapter)
  • Supports multiple tokens from different client-ids in the frontend

Verified to work with following OIDC servers/ services

*) If you have successfully used this client with other OIDC Servers please let us know through a PR or Issue.

See example application for testing at ./example. Start with npm run example.

Usage

import Client from 'oidc-connector'

const client = new Client({
  url: 'http://localhost:8080/auth',
  clientId: 'my-app'
})

// subscribe to events
client.on('token', ({token, tokenParsed}) => {
  if (!token) {
    startSilentLogin()
    // alternatively you may use
    // startLogin()
  } else {
    // do sth. with the tokens
  }
})
client.on('logout', () => {
  // option `forceLogout` is set to true by default; No need to react here
})
client.on('error', (err) => {
  // get notified on errors
})
client.on('action', ({status}) => {
  // subscribe to actions
  // see https://github.com/keycloak/keycloak-community/blob/main/design/application-initiated-actions.md
})

// always initialize on page load!!!
await client.init().catch(err => {
  // react here on initialisation errors; error is also emitted as event
  startLogin()
})

/**
 * Starts login procedure
 * User will always be prompted for credentials.
 */
const startLogin = () => {
  client.login().catch(err => {
    // react here on login errors; error is also emitted as event
  })
}

/**
 * Silent login checks via iframe if auth session exists.
 * Requires option `silentLoginRedirectUri` with server side redirect page.
 * May be blocked if 3rd party cookies are rejected by browser.
 * The below snippet tries to login a user silently (assuming user is
 * already logged-in) at first to later redirect to the auth server for final login.
 */
const startSilentLogin = () => {
  client.silentLogin({prompt: 'none'}).catch(err => {
    if (err.message === 'login_required') {
      startLogin ()
    }
  })
}

for later using the token in communications (e.g. RESTful)

const token = await client.accessToken()
const res = await fetch('http://example.org', {
  headers: {
    Authorization: `Bearer ${token}`,
    Accept: 'application/json'
  }
})
const body = await res.json()
if (res.status === 200) {
  // handle response
} else {
  // handle error response
}

For an example using a React/ Preact Application see ./example/src/OidcConnector.jsx

Configuration

from ./src/client.d.ts

export interface Options {
  /**
   * URL to the OIDC server.
   * This URL is used to locate the OIDC discovery document (typically found
   * at /.well-known/openid-configuration), which specifies the provider's
   * OAuth endpoints and public keys.
   */
  url: string;
  /**
   * Name of the realm (applies only to keycloak servers)
   */
  realm?: string;
  /**
   * Client identifier example: 'my-app'
   */
  clientId: string;
  /**
   * Client Secret (for servers which require basic-auth)
   * token_endpoint_auth_methods_supported: ['client_secret_basic']
   */
  clientSecret?: string;
  /**
   * Send Client Secret in POST body. 
   * token_endpoint_auth_methods_supported: ['client_secret_post']
   */
  clientSecretPost?: boolean;
  /**
   * Specifies a default uri to redirect to after login or logout.
   */
  redirectUri?: Url;
  /**
   * Specifies a default uri to redirect to after logout.
   * if not specified than value from `redirectUri` is used.
   */
  postLogoutRedirectUri?: Url;
  /**
   * Replaces the settings which are usually loaded from
   * `.well-known/openid-configuration`.
   * Needs to follow the conventions defined in the standard.
   * https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderMetadata
   * If type is string than configuration is loaded from this url.
   */
  oidcConfig?: OidcConfig | string;
  /**
   * calls login on client initialization if no valid tokens are present
   * @default false
   */
  forceLogin?: boolean;
  /**
   * calls logout if event 'logout' was emitted.
   * @default true
   */
  forceLogout?: boolean;
  /**
   * OpenID Connect scopes.
   * Scope `openid` is always added per default.
   */
  scope?: string|string[];
  /**
   * Adds a [cryptographic nonce](https://en.wikipedia.org/wiki/Cryptographic_nonce)
   * to verify that the authentication response matches the request.
   * @default true
   */
  useNonce?: boolean;
  /**
   * storage used to store received tokens.
   * @default 'session'
   */
  storage?: 'session'|'local'|'cookie'|'memory'|'none';
  /**
   * minimum validity of an access_token before expiry.
   * If expiry is less than minValidity new access_token is requested using a
   * refresh_token.
   * @default 15
   */
  minValidity?: number;
  /**
   * timer interval (in seconds) to check if token needs update
   * @default 5
   */
  expiryInterval?: number;
  /**
   * Set the OpenID Connect response mode upon login.
   * @default fragment After successful authentication the OIDC server will
   *                   redirect to JavaScript application with OpenID Connect
   *                   parameters added in URL fragment. This is generally safer
   *                   and recommended over 'query'.
   */
  responseMode?: ResponseMode;
  /**
   * Set the OpenID Connect response type upon login
   * @default code
   */
  responseType?: ResponseType;
  /**
   * Set the OpenID Connect flow.
   * @default standard
   */
  flow?: 'standard'|'implicit'|'hybrid';
  /**
   * Configures the Proof Key for Code Exchange (PKCE) method to use.
   * The currently allowed method is 'S256'.
   * If not configured, PKCE will not be used.
   */
  pkceMethod?: PkceMethod;
  /**
   * external function which implements the PKCE challenge.
   * If not configured, PKCE will not be used.
   */
  pkce?: (pkceMethod: PkceMethod) => { codeVerifier: string, challenge: string };
  /**
   * Set to enable/disable session monitoring login state.
   * @default true
   */
  useStatusIframe?: boolean;
  /**
   * Set the interval to check login state (in seconds).
   * @default 5
   */
  statusIframeInterval?: number;
  /**
   * define a custom adapter e.g. for use with cordova
   * @default as defined in adapters/default.js
   */
  adapter?: Adapter;
  /**
   * Set an initial value for the token.
   */
  token?: string;
  /**
   * Set an initial value for the refresh token.
   */
  refreshToken?: string;
  /**
   * Set an initial value for the id token
   */
  idToken?: string;
  /**
   * Specifies an uri to redirect to after silent login was triggered.
   * Silent login will only happen, when this redirect uri is given and the
   * specified uri is available within the application.
   * The url must deliver a page with the following content.
   * ```
   * <html><body><script>
   *   parent.postMessage(location.href, location.origin);
   * </script></body></html>
   * ```
   */
  silentLoginRedirectUri?: string;
  /**
   * Seconds to wait for the silent login redirect iframe to load
   * @default 5
   */
  silentLoginWait?: number;
  /**
   * log output using `log.info` and `log.error`
   * example: {log: console, ...}
   */
  log?: Logger;
  /**
   * By default the login screen is displayed if the user is not logged in.
   * To only authenticate to the application if the user is already
   * logged in and not display the login page if the user is not logged in, set
   * this option to `'none'`. To always require re-authentication and ignore
   * SSO, set this option to `'login'`.
   */
  prompt?: 'none'|'login';
  /**
   * Used just if user is already authenticated. Specifies maximum time since
   * the authentication of user happened. If user is already authenticated for
   * longer time than `'maxAge'`, the SSO is ignored and he will need to
   * authenticate again.
   */
  maxAge?: number;
  /**
   * Used to pre-fill the username/email field on the login form.
   */
  loginHint?: string;
  /**
   * Used to tell then OIDC server which Identity Provider (IDP) the user wants
   * to authenticate with. Needs to be supported by OIDC server
   */
  idpHint?: string;
  /**
   * Sets the 'ui_locales' query param in compliance with section 3.1.2.1
   * of the OIDC 1.0 specification.
   */
  locale?: string;
  /**
   * additional authorization paramaters added on authorization request
   */
  authorizationParams?: object;
  /**
   * registration endpoint for users
   */
  userRegistrationEndpoint?: Url;
  /**
   * account endpoint for users
   */
  userAccountEndpoint?: Url;
}

/**
 * Standard data is taken from `.well-known/oidc-configuration` endpoint
 * non-standard settings can be named here.
 * @see https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderMetadata
 */
export interface OidcConfig {
  /** issuer url shall be the same as `url` */
  issuer?: Url;
  /** certificates endpoint */
  jwks_uri?: Url;
  /** authorization endpoint */
  authorization_endpoint?: Url;
  /** token endpoint */
  token_endpoint?: Url;
  /** userinfo endpoint */
  userinfo_endpoint?: Url;
  /** logout endpoint */
  end_session_endpoint?: Url;
  /** session management endpoint */
  check_session_iframe?: Url;
}

/**
 * logger with log levels. Uses '%s' microformat options
 * Either use with `console` or [debug](https://www.npmjs.com/package/debug)
 */
export interface Logger {
  /** logs info messages */
  info?: (...args: any) => void;
  /** logs error messages */
  error?: (...args: any) => void;
}

export interface Tokens {
  /**
   * raw access token
   */
  token?: string;
  /**
   * payload of access token (only if JWT)
   */
  tokenParsed?: object;
  /**
   * raw id token
   */
  idToken?: string;
  /**
   * payload of id token
   */
  idTokenParsed?: object;
  /**
   * raw refresh token
   */
  refreshToken?: string;
  /**
   * payload of refresh token (only if JWT)
   */
  refreshTokenParsed?: object;
  /**
   * obtain claim by claim name. E.g. `sub` returns subject
   * First id token payload is checked. If not available then access token
   * payload is queried.
   */
  claim: (claimName: string) => string | number | undefined;
}

export type eventName = 'token'|'error'|'logout'|'action'

export class Client extends EventEmitter {
  constructor (options: Options);
  /**
   * initialize the client. Needs to be called on page load.
   */
  init () : Promise<any>;
  /**
   * adds listener to eventName
   */
  on (eventName: eventName, listener: Function) : this;
  /**
   * removes listener to eventName
   */
  off (eventName: eventName, listener: Function) : this;
  /**
   * return all available tokens and its parsed payload
   */
  getTokens(): Tokens;
  /**
   * asynchonously return access token
   */
  accessToken(): Promise<Tokens["token"]>
  /**
   * Starts login procedure
   * User will always be prompted for credentials.
   * Set prompt='none' if login shall not prompt for credentials.
   */
  login(opts?: {prompt?: 'none'}): Promise<undefined>;
  /**
   * Silent login checks via iframe if auth session exists.
   * Requires option `silentLoginRedirectUri` with server side redirect page.
   * May be blocked if 3rd party cookies are rejected by browser.
   * If opts.prompt is set then `login()` will be started.
   * For `{prompt: 'login'}` user is prompted for credentials.
   * With `{prompt: 'none'}` user is not prompted for credentials (has same effect
   * as with `silentLoginRedirectUri` but with page redirects)
   */
  silentLogin (opts?: {prompt?: 'none'|'login'}): Promise<undefined>;
  /**
   * starts logout
   */
  logout (): Promise<any>;
  /**
   * starts registration
   */
  register (): Promise<any>;
  /**
   * redirects to account management
   */
  account (): Promise<any>;
}

Testing

Utility functions and client are tested with jsdom.

npm t

The Client can be tested with client and server running in different terminals.

# starts app on localhost:8000
npm run dev
# starts oidc server on localhost:3000
npm run dev:server

License

Apache 2.0

References