安装
npm install openid-client
yarn add openid-client
pnpm add openid-client
bun add openid-client
README

openid-client

OAuth 2 / OpenID Connect Client API for JavaScript Runtimes

openid-client simplifies integration with authorization servers by providing easy-to-use APIs for the most common authentication and authorization flows, including OAuth 2 and OpenID Connect. It is designed for JavaScript runtimes like Node.js, Browsers, Deno, Cloudflare Workers, and more.

Features

The following features are currently in scope and implemented in this software:

  • Authorization Server Metadata discovery
  • Authorization Code Flow (profiled under OpenID Connect 1.0, OAuth 2.0, OAuth 2.1, FAPI 1.0 Advanced, and FAPI 2.0)
  • Refresh Token, Device Authorization, Client-Initiated Backchannel Authentication (CIBA), and Client Credentials Grants
  • Demonstrating Proof-of-Possession at the Application Layer (DPoP)
  • Token Introspection and Revocation
  • Pushed Authorization Requests (PAR)
  • UserInfo and Protected Resource Requests
  • Authorization Server Issuer Identification
  • JWT Secured Introspection, Response Mode (JARM), Authorization Request (JAR), and UserInfo
  • Dynamic Client Registration (DCR)
  • Passport Strategy
Auth0 by Okta

If you want to quickly add authentication to JavaScript apps, feel free to check out Auth0's JavaScript SDK and free plan. Create an Auth0 account; it's free!

Certification

OpenID Certification

Filip Skokan has certified that this software conforms to the Basic, FAPI 1.0, and FAPI 2.0 Relying Party Conformance Profiles of the OpenID Connect™ protocol.

💗 Help the project

Support from the community to continue maintaining and improving this module is welcome. If you find the module useful, please consider supporting the project by becoming a sponsor.

API Reference Documentation

openid-client is distributed via npmjs.com, jsr.io, and github.com.

Examples

example ESM import[^cjs]

import * as client from 'openid-client'
  • Authorization Code Flow (OAuth 2.0) - source
  • Authorization Code Flow (OpenID Connect) - source | diff
  • Extensions
  • Passport Strategy - source

Quick start

let server!: URL // Authorization Server's Issuer Identifier
let clientId!: string // Client identifier at the Authorization Server
let clientSecret!: string // Client Secret

let config: client.Configuration = await client.discovery(
  server,
  clientId,
  clientSecret,
)

Authorization Code Flow

Authorization Code flow is for obtaining Access Tokens (and optionally Refresh Tokens) to use with third party APIs.

When you want to have your end-users authorize or authenticate you need to send them to the authorization server's authorization_endpoint. Consult the web framework of your choice on how to redirect but here's how to get the authorization endpoint's URL with parameters already encoded in the query to redirect to.

/**
 * Value used in the authorization request as the redirect_uri parameter, this
 * is typically pre-registered at the Authorization Server.
 */
let redirect_uri!: string
let scope!: string // Scope of the access request
/**
 * PKCE: The following MUST be generated for every redirect to the
 * authorization_endpoint. You must store the code_verifier and state in the
 * end-user session such that it can be recovered as the user gets redirected
 * from the authorization server back to your application.
 */
let code_verifier: string = client.randomPKCECodeVerifier()
let code_challenge: string =
  await client.calculatePKCECodeChallenge(code_verifier)
let state!: string

let parameters: Record<string, string> = {
  redirect_uri,
  scope,
  code_challenge,
  code_challenge_method: 'S256',
}

if (!config.serverMetadata().supportsPKCE()) {
  /**
   * We cannot be sure the server supports PKCE so we're going to use state too.
   * Use of PKCE is backwards compatible even if the AS doesn't support it which
   * is why we're using it regardless. Like PKCE, random state must be generated
   * for every redirect to the authorization_endpoint.
   */
  state = client.randomState()
  parameters.state = state
}

let redirectTo: URL = client.buildAuthorizationUrl(config, parameters)

// now redirect the user to redirectTo.href
console.log('redirecting to', redirectTo.href)

When end-users are redirected back to the redirect_uri your application consumes the callback and passes in PKCE code_verifier to include it in the authorization code grant token exchange.

let getCurrentUrl!: (...args: any) => URL

let tokens: client.TokenEndpointResponse = await client.authorizationCodeGrant(
  config,
  getCurrentUrl(),
  {
    pkceCodeVerifier: code_verifier,
    expectedState: state,
  },
)

console.log('Token Endpoint Response', tokens)

You can then fetch a protected resource response

let protectedResourceResponse: Response = await client.fetchProtectedResource(
  config,
  tokens.access_token,
  new URL('https://rs.example.com/api'),
  'GET',
)

console.log(
  'Protected Resource Response',
  await protectedResourceResponse.json(),
)

Device Authorization Grant (Device Flow)

let scope!: string // Scope of the access request

let response = await client.initiateDeviceAuthorization(config, { scope })

console.log('User Code:', response.user_code)
console.log('Verification URI:', response.verification_uri)
console.log('Verification URI (complete):', response.verification_uri_complete)

You will display the instructions to the end-user and have them directed at verification_uri or verification_uri_complete, afterwards you can start polling for the Device Access Token Response.

let tokens: client.TokenEndpointResponse =
  await client.pollDeviceAuthorizationGrant(config, response)

console.log('Token Endpoint Response', tokens)

This will poll in a regular interval and only resolve with tokens once the end-user authenticates.

Client-Initiated Backchannel Authentication (CIBA)

let scope!: string // Scope of the access request
/**
 * One of login_hint, id_token_hint, or login_hint_token parameters must be
 * provided in CIBA
 */
let login_hint!: string

let response = await client.initiateBackchannelAuthentication(config, {
  scope,
  login_hint,
})

/**
 * OPTIONAL: If your client is configured with Ping Mode you'd invoke the
 * following after getting the CIBA Ping Callback (its implementation is
 * framework specific and therefore out of scope for openid-client)
 */

let tokens: client.TokenEndpointResponse =
  await client.pollBackchannelAuthenticationGrant(config, response)

console.log('Token Endpoint Response', tokens)

This will poll in a regular interval and only resolve with tokens once the end-user authenticates.

Client Credentials Grant

Client Credentials flow is for obtaining Access Tokens to use with third party APIs on behalf of your application, rather than an end-user which was the case in previous examples.

let scope!: string // Scope of the access request
let resource!: string // Resource Indicator of the Resource Server the access token is for

let tokens: client.TokenEndpointResponse = await lib.clientCredentialsGrant(
  config,
  { scope, resource },
)

console.log('Token Endpoint Response', tokens)

Supported Runtimes

The supported JavaScript runtimes include those that support the utilized Web API globals and standard built-in objects. These are (but are not limited to):

  • Browsers
  • Bun
  • Cloudflare Workers
  • Deno
  • Electron
  • Node.js[^nodejs]

Supported Versions

Version Security Fixes 🔑 Other Bug Fixes 🐞 New Features ⭐ Runtime and Module type
v6.x Security Policy Universal[^universal] ESM[^cjs]
v5.x Security Policy Node.js CJS + ESM

[^nodejs]: Node.js v20.x as baseline is required

[^universal]: Assumes runtime support of WebCryptoAPI and Fetch API

[^cjs]: CJS style let client = require('openid-client') is possible in Node.js versions where the require(esm) feature is enabled by default (^20.19.0 || ^22.12.0 || >= 23.0.0).

版本列表
6.8.4 2026-04-27
6.8.3 2026-04-13
6.8.2 2026-02-07
6.8.1 2025-09-27
6.8.0 2025-09-11
6.7.1 2025-08-29
6.7.0 2025-08-27
6.6.4 2025-08-12
6.6.3 2025-08-05
6.6.2 2025-07-01
6.6.1 2025-06-21
6.6.0 2025-06-21
6.5.3 2025-06-19
6.5.2 2025-06-19
6.5.1 2025-06-08
6.5.0 2025-05-06
6.4.2 2025-04-10
6.4.1 2025-04-03
6.4.0 2025-04-03
6.3.4 2025-03-12
6.3.3 2025-02-24
6.3.2 2025-02-24
6.3.1 2025-02-20
6.3.0 2025-02-18
6.2.0 2025-02-17
6.1.7 2024-12-02
6.1.6 2024-11-28
6.1.5 2024-11-27
6.1.4 2024-11-22
6.1.3 2024-10-23
6.1.2 2024-10-23
6.1.1 2024-10-18
6.1.0 2024-10-17
6.0.0-beta.2 2024-10-14
6.0.0-beta.1 2024-10-12
6.0.0-beta.0 2024-10-07
6.0.0 2024-10-15
5.7.1 2024-11-22
5.7.0 2024-09-09
5.6.5 2024-03-07
5.6.4 2024-01-06
5.6.3 2024-01-05
5.6.2 2023-12-22
5.6.1 2023-10-11
5.6.0 2023-10-03
5.5.0 2023-09-08
5.4.3 2023-07-06
5.4.2 2023-04-25
5.4.1 2023-04-21
5.4.0 2023-02-05
5.3.4 2023-02-02
5.3.3 2023-02-02
5.3.2 2023-01-20
5.3.1 2022-11-28
5.3.0 2022-11-09
5.2.1 2022-10-20
5.2.0 2022-10-19
5.1.10 2022-09-28
5.1.9 2022-08-23
5.1.8 2022-07-04
5.1.7 2022-06-25
5.1.6 2022-05-10
5.1.5 2022-04-14
5.1.4 2022-03-04
5.1.3 2022-02-03
5.1.2 2022-01-13
5.1.1 2021-12-20
5.1.0 2021-12-03
5.0.2 2021-10-28
5.0.1 2021-10-27
5.0.0 2021-10-27
4.9.1 2021-10-13
4.9.0 2021-09-20
4.8.0 2021-09-15
4.7.5 2021-08-30
4.7.4 2021-05-25
4.7.3 2021-04-30
4.7.2 2021-04-23
4.7.1 2021-04-22
4.7.0 2021-04-22
4.6.0 2021-03-25
4.5.2 2021-03-24
4.5.1 2021-03-15
4.5.0 2021-03-10
4.4.2 2021-03-07
4.4.1 2021-02-26
4.4.0 2021-01-29
4.3.0 2021-01-22
4.2.3 2021-01-18
4.2.2 2020-11-30
4.2.1 2020-10-27
4.2.0 2020-10-03
4.1.1 2020-09-14
4.1.0 2020-09-11
4.0.2 2020-09-11
4.0.1 2020-09-10
4.0.0 2020-09-09
3.15.10 2020-09-02
3.15.9 2020-07-26
3.15.8 2020-07-17
3.15.7 2020-07-16
3.15.6 2020-07-06
3.15.5 2020-06-26
3.15.4 2020-06-26
3.15.3 2020-06-15
3.15.2 2020-06-01
3.15.1 2020-05-12
3.15.0 2020-04-28
3.14.2 2020-04-07
3.14.1 2020-03-21
3.14.0 2020-02-28
3.13.0 2020-02-18
3.12.2 2020-01-30
3.12.1 2020-01-25
3.12.0 2020-01-23
3.11.0 2020-01-10
3.10.1 2020-01-07
3.10.0 2019-12-27
3.9.2 2019-12-17
3.9.1 2019-12-15
3.9.0 2019-12-06
3.8.4 2019-11-26
3.8.3 2019-11-14
3.8.2 2019-11-10
3.8.1 2019-11-07
3.8.0 2019-11-07
3.7.4 2019-10-24
3.7.3 2019-10-01
3.7.2 2019-09-13
3.7.1 2019-09-09
3.7.0 2019-09-09
3.6.2 2019-09-03
3.6.1 2019-08-24
3.6.0 2019-08-24
3.5.0 2019-08-22
3.4.0 2019-08-13
3.3.0 2019-08-02
3.2.3 2019-07-18
3.2.2 2019-07-12
3.2.1 2019-07-10
3.2.0 2019-06-27
3.1.2 2019-06-21
3.1.1 2019-05-15
3.1.0 2019-05-13
3.0.0 2019-05-11
2.5.0 2019-04-29
2.4.5 2018-11-05
2.4.4 2018-10-18
2.4.3 2018-10-10
2.4.2 2018-09-27
2.4.1 2018-09-16
2.3.1 2018-08-23
2.3.0 2018-08-11
2.2.1 2018-07-10
2.2.0 2018-07-04
2.1.1 2018-06-28
2.1.0 2018-05-31
2.0.4 2018-05-25
2.0.3 2018-05-15
2.0.2 2018-05-10
2.0.1 2018-04-26
2.0.0 2018-04-12
1.20.0 2018-03-13
1.19.5 2018-03-10
1.19.4 2018-01-30
1.19.3 2018-01-22
1.19.2 2018-01-16
1.19.1 2018-01-15
1.19.0 2017-12-12
1.18.2 2017-12-05
1.18.1 2017-11-25
1.18.0 2017-11-19
1.17.0 2017-10-31
1.16.0 2017-10-13
1.15.0 2017-09-11
1.14.0 2017-09-09
1.13.0 2017-08-24
1.12.1 2017-08-11
1.12.0 2017-07-17
1.11.1 2017-07-14
1.11.0 2017-05-19
1.10.0 2017-05-04
1.9.0 2017-04-30
1.8.2 2017-04-29
1.8.1 2017-04-13
1.8.0 2017-04-07
1.7.2 2017-03-28
1.7.1 2017-03-28
1.6.4 2017-03-14
1.6.3 2017-03-14
1.6.2 2017-03-09
1.6.1 2017-03-07
1.6.0 2017-02-15
1.5.3 2017-02-15
1.5.2 2017-02-01
1.5.1 2017-01-29
1.5.0 2017-01-26
1.4.0 2017-01-10
1.3.1 2016-12-18
1.3.0 2016-12-13
1.2.0 2016-12-09
1.1.0 2016-11-23
1.0.2 2016-11-22
1.0.1 2016-11-18
1.0.0 2016-11-17
0.7.0 2016-11-02
0.6.1 2016-10-24
0.6.0 2016-09-21
0.5.4 2016-09-15
0.5.3 2016-09-11
0.5.2 2016-09-10
0.5.1 2016-08-18
0.5.0 2016-08-09
0.4.1 2016-08-04
0.4.0 2016-08-04
0.3.0 2016-07-28
0.2.0 2016-07-26
0.1.0 2016-07-14
0.0.1 2016-07-08