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.
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

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!
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.
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.
openid-client is distributed via npmjs.com, jsr.io, and github.com.
example ESM import1
import*asclientfrom'openid-client'- Authorization Code Flow (OAuth 2.0) - source
- Authorization Code Flow (OpenID Connect) - source | diff
- Extensions
- Passport Strategy - source
letserver!: URL// Authorization Server's Issuer IdentifierletclientId!: string// Client identifier at the Authorization ServerletclientSecret!: string// Client Secretletconfig: client.Configuration=awaitclient.discovery(server,clientId,clientSecret,)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. */letredirect_uri!: stringletscope!: 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. */letcode_verifier: string=client.randomPKCECodeVerifier()letcode_challenge: string=awaitclient.calculatePKCECodeChallenge(code_verifier)letstate!: stringletparameters: 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}letredirectTo: URL=client.buildAuthorizationUrl(config,parameters)// now redirect the user to redirectTo.hrefconsole.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.
letgetCurrentUrl!: (...args: any)=>URLlettokens: client.TokenEndpointResponse=awaitclient.authorizationCodeGrant(config,getCurrentUrl(),{pkceCodeVerifier: code_verifier,expectedState: state,},)console.log('Token Endpoint Response',tokens)You can then fetch a protected resource response
letprotectedResourceResponse: Response=awaitclient.fetchProtectedResource(config,tokens.access_token,newURL('https://rs.example.com/api'),'GET',)console.log('Protected Resource Response',awaitprotectedResourceResponse.json(),)letscope!: string// Scope of the access requestletresponse=awaitclient.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.
lettokens: client.TokenEndpointResponse=awaitclient.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.
letscope!: string// Scope of the access request/** * One of login_hint, id_token_hint, or login_hint_token parameters must be * provided in CIBA */letlogin_hint!: stringletresponse=awaitclient.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) */lettokens: client.TokenEndpointResponse=awaitclient.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 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.
letscope!: string// Scope of the access requestletresource!: string// Resource Indicator of the Resource Server the access token is forlettokens: client.TokenEndpointResponse=awaitlib.clientCredentialsGrant(config,{ scope, resource },)console.log('Token Endpoint Response',tokens)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.js2
| Version | Security Fixes 🔑 | Other Bug Fixes 🐞 | New Features ⭐ | Runtime and Module type |
|---|---|---|---|---|
| v6.x | Security Policy | ✅ | ✅ | Universal3 ESM1 |
