mirror of
https://github.com/hanzoai/openid-client.git
synced 2026-09-24 17:01:10 +00:00
100 lines
2.7 KiB
TypeScript
100 lines
2.7 KiB
TypeScript
import * as client from 'openid-client'
|
|
|
|
// Prerequisites
|
|
|
|
let getCurrentUrl!: (...args: any) => URL
|
|
let server!: URL // Authorization server's Issuer Identifier URL
|
|
let clientId!: string
|
|
let clientSecret!: string
|
|
/**
|
|
* Value used in the authorization request as redirect_uri pre-registered at the
|
|
* Authorization Server.
|
|
*/
|
|
let redirect_uri!: string
|
|
|
|
/**
|
|
* In order to take full advantage of DPoP you shall generate a random key pair
|
|
* for every session. In the browser environment you shall use IndexedDB to
|
|
* persist the generated CryptoKeyPair.
|
|
*/
|
|
let DPoPKeys!: client.CryptoKeyPair
|
|
|
|
// End of prerequisites
|
|
|
|
let config = await client.discovery(server, clientId, clientSecret)
|
|
|
|
let DPoP = client.getDPoPHandle(config, DPoPKeys)
|
|
|
|
let code_challenge_method = 'S256'
|
|
/**
|
|
* The following (code_verifier and potentially state) 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 = client.randomPKCECodeVerifier()
|
|
let code_challenge = await client.calculatePKCECodeChallenge(code_verifier)
|
|
let state!: string
|
|
|
|
{
|
|
// redirect user to as.authorization_endpoint
|
|
let parameters: Record<string, string> = {
|
|
redirect_uri,
|
|
scope: 'api:read',
|
|
code_challenge,
|
|
code_challenge_method,
|
|
}
|
|
|
|
/**
|
|
* We cannot be sure the AS 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.
|
|
*/
|
|
if (!config.serverMetadata().supportsPKCE()) {
|
|
state = client.randomState()
|
|
parameters.state = state
|
|
}
|
|
|
|
let redirectTo = client.buildAuthorizationUrl(config, parameters)
|
|
|
|
console.log('redirecting to', redirectTo.href)
|
|
// now redirect the user to redirectTo.href
|
|
}
|
|
|
|
// one eternity later, the user lands back on the redirect_uri
|
|
// Authorization Code Grant
|
|
let access_token: string
|
|
let token_type: string
|
|
{
|
|
let currentUrl: URL = getCurrentUrl()
|
|
let tokens = await client.authorizationCodeGrant(
|
|
config,
|
|
currentUrl,
|
|
{
|
|
pkceCodeVerifier: code_verifier,
|
|
expectedState: state,
|
|
},
|
|
undefined,
|
|
{ DPoP },
|
|
)
|
|
|
|
console.log('Token Endpoint Response', tokens)
|
|
;({ access_token, token_type } = tokens)
|
|
}
|
|
|
|
// Protected Resource Request
|
|
{
|
|
let protectedResource = await client.fetchProtectedResource(
|
|
config,
|
|
access_token,
|
|
new URL('https://rs.example.com/api'),
|
|
'GET',
|
|
undefined,
|
|
undefined,
|
|
token_type === 'dpop' ? { DPoP } : undefined,
|
|
)
|
|
|
|
console.log('Protected Resource Response', await protectedResource.json())
|
|
}
|