Skip to content

Commit

Permalink
docs: update all examples
Browse files Browse the repository at this point in the history
  • Loading branch information
panva committed Feb 7, 2024
1 parent bcbc872 commit cdcbbde
Show file tree
Hide file tree
Showing 29 changed files with 1,617 additions and 446 deletions.
30 changes: 20 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,16 +47,26 @@ import * as oauth2 from 'oauth4webapi'
import * as oauth2 from 'https://deno.land/x/oauth4webapi@v2.10.2/mod.ts'
```

- Authorization Code Flow - OpenID Connect [source](examples/code.ts), or plain OAuth 2 [source](examples/oauth.ts)
- Public Client Authorization Code Flow - [source](examples/public.ts) | [diff from code flow](examples/public.diff)
- Private Key JWT Client Authentication - [source](examples/private_key_jwt.ts) | [diff from code flow](examples/private_key_jwt.diff)
- DPoP - [source](examples/dpop.ts) | [diff from code flow](examples/dpop.diff)
- Pushed Authorization Request (PAR) - [source](examples/par.ts) | [diff from code flow](examples/par.diff)
- Client Credentials Grant - [source](examples/client_credentials.ts)
- Device Authorization Grant - [source](examples/device_authorization_grant.ts)
- FAPI 1.0 Advanced (Private Key JWT, MTLS, JAR) - [source](examples/fapi1-advanced.ts)
- FAPI 2.0 Security Profile (Private Key JWT, PAR, DPoP) - [source](examples/fapi2.ts)
- FAPI 2.0 Message Signing (Private Key JWT, PAR, DPoP, JAR, JARM) - [source](examples/fapi2-message-signing.ts) | [diff from FAPI 2.0 SP](examples/fapi2-message-signing.diff)
- Authorization Code Flow (OAuth 2.0) - [source](examples/oauth.ts)
- Authorization Code Flow (OpenID Connect) - [source](examples/oidc.ts) | [diff](examples/oidc.diff)
- Extensions
- DPoP - [source](examples/dpop.ts) | [diff](examples/dpop.diff)
- JWT Secured Authorization Request (JAR) - [source](examples/jar.ts) | [diff](examples/jar.diff)
- JWT Secured Authorization Response Mode (JARM) - [source](examples/jarm.ts) | [diff](examples/jarm.diff)
- Pushed Authorization Request (PAR) - [source](examples/par.ts) | [diff](examples/par.diff)
- Client Authentication
- Client Secret in HTTP Authorization Header - [source](examples/oauth.ts)
- Client Secret in HTTP Body - [source](examples/client_secret_post.ts) | [diff](examples/client_secret_post.diff)
- Private Key JWT Client Authentication - [source](examples/private_key_jwt.ts) | [diff](examples/private_key_jwt.diff)
- Public Client - [source](examples/public.ts) | [diff](examples/public.diff)
- Other Grants
- Client Credentials Grant - [source](examples/client_credentials.ts)
- Device Authorization Grant - [source](examples/device_authorization_grant.ts)
- Refresh Token Grant - [source](examples/refresh_token.ts) | [diff](examples/refresh_token.diff)
- FAPI
- FAPI 1.0 Advanced (Private Key JWT, MTLS, JAR) - [source](examples/fapi1-advanced.ts) | [diff](examples/fapi1-advanced.diff)
- FAPI 2.0 Security Profile (Private Key JWT, PAR, DPoP) - [source](examples/fapi2.ts) | [diff](examples/fapi2.diff)


## Supported Runtimes

Expand Down
16 changes: 11 additions & 5 deletions examples/.update-diffs.sh
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
git diff HEAD:examples/code.ts examples/dpop.ts > examples/dpop.diff
git diff HEAD:examples/code.ts examples/par.ts > examples/par.diff
git diff HEAD:examples/code.ts examples/private_key_jwt.ts > examples/private_key_jwt.diff
git diff HEAD:examples/code.ts examples/public.ts > examples/public.diff
git diff HEAD:examples/fapi2.ts examples/fapi2-message-signing.ts > examples/fapi2-message-signing.diff
git diff HEAD:examples/oauth.ts examples/oidc.ts > examples/oidc.diff
git diff HEAD:examples/oauth.ts examples/dpop.ts > examples/dpop.diff
git diff HEAD:examples/oauth.ts examples/par.ts > examples/par.diff
git diff HEAD:examples/oauth.ts examples/jar.ts > examples/jar.diff
git diff HEAD:examples/oauth.ts examples/jarm.ts > examples/jarm.diff
git diff HEAD:examples/oauth.ts examples/client_secret_post.ts > examples/client_secret_post.diff
git diff HEAD:examples/oauth.ts examples/private_key_jwt.ts > examples/private_key_jwt.diff
git diff HEAD:examples/oauth.ts examples/public.ts > examples/public.diff
git diff HEAD:examples/oauth.ts examples/fapi2.ts > examples/fapi2.diff
git diff HEAD:examples/oauth.ts examples/fapi1-advanced.ts > examples/fapi1-advanced.diff
git diff HEAD:examples/oauth.ts examples/refresh_token.ts > examples/refresh_token.diff
29 changes: 19 additions & 10 deletions examples/README.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,21 @@
A collection of examples for the most common use cases.

- Authorization Code Flow - OpenID Connect [source](code.ts), or plain OAuth 2 [source](oauth.ts)
- Public Client Authorization Code Flow - [source](public.ts) | [diff from code flow](public.diff)
- Private Key JWT Client Authentication - [source](private_key_jwt.ts) | [diff from code flow](private_key_jwt.diff)
- DPoP - [source](dpop.ts) | [diff from code flow](dpop.diff)
- Pushed Authorization Request (PAR) - [source](par.ts) | [diff from code flow](par.diff)
- Client Credentials Grant - [source](client_credentials.ts)
- Device Authorization Grant - [source](device_authorization_grant.ts)
- FAPI 1.0 Advanced (Private Key JWT, MTLS, JAR) - [source](fapi1-advanced.ts)
- FAPI 2.0 Security Profile (Private Key JWT, PAR, DPoP) - [source](fapi2.ts)
- FAPI 2.0 Message Signing (Private Key JWT, PAR, DPoP, JAR, JARM) - [source](fapi2-message-signing.ts) | [diff from FAPI 2.0 SP](fapi2-message-signing.diff)
- Authorization Code Flow (OAuth 2.0) - [source](oauth.ts)
- Authorization Code Flow (OpenID Connect) - [source](oidc.ts) | [diff](oidc.diff)
- Extensions
- DPoP - [source](dpop.ts) | [diff](dpop.diff)
- JWT Secured Authorization Request (JAR) - [source](jar.ts) | [diff](jar.diff)
- JWT Secured Authorization Response Mode (JARM) - [source](jarm.ts) | [diff](jarm.diff)
- Pushed Authorization Request (PAR) - [source](par.ts) | [diff](par.diff)
- Client Authentication
- Client Secret in HTTP Authorization Header - [source](oauth.ts)
- Client Secret in HTTP Body - [source](client_secret_post.ts) | [diff](client_secret_post.diff)
- Private Key JWT Client Authentication - [source](private_key_jwt.ts) | [diff](private_key_jwt.diff)
- Public Client - [source](public.ts) | [diff](public.diff)
- Other Grants
- Client Credentials Grant - [source](client_credentials.ts)
- Device Authorization Grant - [source](device_authorization_grant.ts)
- Refresh Token Grant - [source](refresh_token.ts) | [diff](refresh_token.diff)
- FAPI
- FAPI 1.0 Advanced (Private Key JWT, MTLS, JAR) - [source](fapi1-advanced.ts) | [diff](fapi1-advanced.diff)
- FAPI 2.0 Security Profile (Private Key JWT, PAR, DPoP) - [source](fapi2.ts) | [diff](fapi2.diff)
59 changes: 43 additions & 16 deletions examples/client_credentials.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,17 @@ import * as oauth from '../src/index.js' // replace with an import of oauth4weba
// Prerequisites

let issuer!: URL // Authorization server's Issuer Identifier URL
let algorithm!:
| 'oauth2' /* For .well-known/oauth-authorization-server discovery */
| 'oidc' /* For .well-known/openid-configuration discovery */
| undefined /* Defaults to 'oidc' */
let client_id!: string
let client_secret!: string

// End of prerequisites

const as = await oauth
.discoveryRequest(issuer)
.discoveryRequest(issuer, { algorithm })
.then((response) => oauth.processDiscoveryResponse(issuer, response))

const client: oauth.Client = {
Expand All @@ -18,24 +22,47 @@ const client: oauth.Client = {
token_endpoint_auth_method: 'client_secret_basic',
}

const parameters = new URLSearchParams()
parameters.set('scope', 'api:read api:write')
parameters.set('resource', 'urn:example:api')
// Client Credentials Grant Request & Response
let access_token: string
{
const parameters = new URLSearchParams()
parameters.set('scope', 'api:read')

const response = await oauth.clientCredentialsGrantRequest(as, client, parameters)
const response = await oauth.clientCredentialsGrantRequest(as, client, parameters)

let challenges: oauth.WWWAuthenticateChallenge[] | undefined
if ((challenges = oauth.parseWwwAuthenticateChallenges(response))) {
for (const challenge of challenges) {
console.log('challenge', challenge)
let challenges: oauth.WWWAuthenticateChallenge[] | undefined
if ((challenges = oauth.parseWwwAuthenticateChallenges(response))) {
for (const challenge of challenges) {
console.error('WWW-Authenticate Challenge', challenge)
}
throw new Error() // Handle WWW-Authenticate Challenges as needed
}

const result = await oauth.processClientCredentialsResponse(as, client, response)
if (oauth.isOAuth2Error(result)) {
console.error('Error Response', result)
throw new Error() // Handle OAuth 2.0 response body error
}
throw new Error() // Handle www-authenticate challenges as needed
}

const result = await oauth.processClientCredentialsResponse(as, client, response)
if (oauth.isOAuth2Error(result)) {
console.log('error', result)
throw new Error() // Handle OAuth 2.0 response body error
console.log('Access Token Response', result)
;({ access_token } = result)
}

console.log('result', result)
// Protected Resource Request
{
const response = await oauth.protectedResourceRequest(
access_token,
'GET',
new URL('https://rs.example.com/api'),
)

let challenges: oauth.WWWAuthenticateChallenge[] | undefined
if ((challenges = oauth.parseWwwAuthenticateChallenges(response))) {
for (const challenge of challenges) {
console.error('WWW-Authenticate Challenge', challenge)
}
throw new Error() // Handle WWW-Authenticate Challenges as needed
}

console.log('Protected Resource Response', await response.json())
}
13 changes: 13 additions & 0 deletions examples/client_secret_post.diff
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
diff --git a/examples/oauth.ts b/examples/client_secret_post.ts
index cc6d632..df5aefd 100644
--- a/examples/oauth.ts
+++ b/examples/client_secret_post.ts
@@ -24,7 +24,7 @@ const as = await oauth
const client: oauth.Client = {
client_id,
client_secret,
- token_endpoint_auth_method: 'client_secret_basic',
+ token_endpoint_auth_method: 'client_secret_post',
}

const code_challenge_method = 'S256'
117 changes: 117 additions & 0 deletions examples/client_secret_post.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
import * as oauth from '../src/index.js' // replace with an import of oauth4webapi

// Prerequisites

let issuer!: URL // Authorization server's Issuer Identifier URL
let algorithm!:
| 'oauth2' /* For .well-known/oauth-authorization-server discovery */
| 'oidc' /* For .well-known/openid-configuration discovery */
| undefined /* Defaults to 'oidc' */
let client_id!: string
let client_secret!: string
/**
* Value used in the authorization request as redirect_uri pre-registered at the Authorization
* Server.
*/
let redirect_uri!: string

// End of prerequisites

const as = await oauth
.discoveryRequest(issuer, { algorithm })
.then((response) => oauth.processDiscoveryResponse(issuer, response))

const client: oauth.Client = {
client_id,
client_secret,
token_endpoint_auth_method: 'client_secret_post',
}

const code_challenge_method = 'S256'
/**
* The following MUST be generated for every redirect to the authorization_endpoint. You must store
* the code_verifier and nonce in the end-user session such that it can be recovered as the user
* gets redirected from the authorization server back to your application.
*/
const code_verifier = oauth.generateRandomCodeVerifier()
const code_challenge = await oauth.calculatePKCECodeChallenge(code_verifier)
let state: string | undefined

{
// redirect user to as.authorization_endpoint
const authorizationUrl = new URL(as.authorization_endpoint!)
authorizationUrl.searchParams.set('client_id', client.client_id)
authorizationUrl.searchParams.set('redirect_uri', redirect_uri)
authorizationUrl.searchParams.set('response_type', 'code')
authorizationUrl.searchParams.set('scope', 'api:read')
authorizationUrl.searchParams.set('code_challenge', code_challenge)
authorizationUrl.searchParams.set('code_challenge_method', 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 (as.code_challenge_methods_supported?.includes('S256') !== true) {
state = oauth.generateRandomState()
authorizationUrl.searchParams.set('state', state)
}

// now redirect the user to authorizationUrl.href
}

// one eternity later, the user lands back on the redirect_uri
// Authorization Code Grant Request & Response
let access_token: string
{
// @ts-expect-error
const currentUrl: URL = getCurrentUrl()
const params = oauth.validateAuthResponse(as, client, currentUrl, state)
if (oauth.isOAuth2Error(params)) {
console.error('Error Response', params)
throw new Error() // Handle OAuth 2.0 redirect error
}

const response = await oauth.authorizationCodeGrantRequest(
as,
client,
params,
redirect_uri,
code_verifier,
)

let challenges: oauth.WWWAuthenticateChallenge[] | undefined
if ((challenges = oauth.parseWwwAuthenticateChallenges(response))) {
for (const challenge of challenges) {
console.error('WWW-Authenticate Challenge', challenge)
}
throw new Error() // Handle WWW-Authenticate Challenges as needed
}

const result = await oauth.processAuthorizationCodeOAuth2Response(as, client, response)
if (oauth.isOAuth2Error(result)) {
console.error('Error Response', result)
throw new Error() // Handle OAuth 2.0 response body error
}

console.log('Access Token Response', result)
;({ access_token } = result)
}

// Protected Resource Request
{
const response = await oauth.protectedResourceRequest(
access_token,
'GET',
new URL('https://rs.example.com/api'),
)

let challenges: oauth.WWWAuthenticateChallenge[] | undefined
if ((challenges = oauth.parseWwwAuthenticateChallenges(response))) {
for (const challenge of challenges) {
console.error('WWW-Authenticate Challenge', challenge)
}
throw new Error() // Handle WWW-Authenticate Challenges as needed
}

console.log('Protected Resource Response', await response.json())
}
Loading

0 comments on commit cdcbbde

Please sign in to comment.