forked from panva/oauth4webapi
-
Notifications
You must be signed in to change notification settings - Fork 0
/
fapi1-advanced.diff
172 lines (161 loc) · 5.7 KB
/
fapi1-advanced.diff
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
diff --git a/examples/oauth.ts b/examples/fapi1-advanced.ts
index cc6d632..ab605a2 100644
--- a/examples/oauth.ts
+++ b/examples/fapi1-advanced.ts
@@ -1,3 +1,4 @@
+import * as undici from 'undici'
import * as oauth from '../src/index.js' // replace with an import of oauth4webapi
// Prerequisites
@@ -8,12 +9,30 @@ let algorithm!:
| '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
+/**
+ * A key corresponding to the mtlsClientCertificate.
+ */
+let mtlsClientKey!: string
+/**
+ * A certificate the client has pre-registered at the Authorization Server for use with Mutual-TLS
+ * client authentication method.
+ */
+let mtlsClientCertificate!: string
+/**
+ * A key that is pre-registered at the Authorization Server that the client is supposed to sign its
+ * Request Objects with.
+ */
+let jarPrivateKey!: CryptoKey
+/**
+ * A key that the client has pre-registered at the Authorization Server for use with Private Key JWT
+ * client authentication method.
+ */
+let clientPrivateKey!: CryptoKey
// End of prerequisites
@@ -23,8 +42,7 @@ const as = await oauth
const client: oauth.Client = {
client_id,
- client_secret,
- token_endpoint_auth_method: 'client_secret_basic',
+ token_endpoint_auth_method: 'private_key_jwt',
}
const code_challenge_method = 'S256'
@@ -33,39 +51,46 @@ const code_challenge_method = 'S256'
* 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 nonce = oauth.generateRandomNonce()
const code_verifier = oauth.generateRandomCodeVerifier()
const code_challenge = await oauth.calculatePKCECodeChallenge(code_verifier)
-let state: string | undefined
+
+let request: string
+{
+ const params = new URLSearchParams()
+ params.set('client_id', client.client_id)
+ params.set('code_challenge', code_challenge)
+ params.set('code_challenge_method', code_challenge_method)
+ params.set('redirect_uri', redirect_uri)
+ params.set('response_type', 'code id_token')
+ params.set('scope', 'openid api:read')
+ params.set('nonce', nonce)
+
+ request = await oauth.issueRequestObject(as, client, params, jarPrivateKey)
+}
{
// 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)
- }
+ authorizationUrl.searchParams.set('request', request)
// now redirect the user to authorizationUrl.href
}
// one eternity later, the user lands back on the redirect_uri
+// Detached Signature ID Token Validation
// Authorization Code Grant Request & Response
let access_token: string
{
// @ts-expect-error
- const currentUrl: URL = getCurrentUrl()
- const params = oauth.validateAuthResponse(as, client, currentUrl, state)
+ const authorizationResponse: URLSearchParams | URL = getAuthorizationResponseOrURLWithFragment()
+ const params = await oauth.validateDetachedSignatureResponse(
+ as,
+ client,
+ authorizationResponse,
+ nonce,
+ )
if (oauth.isOAuth2Error(params)) {
console.error('Error Response', params)
throw new Error() // Handle OAuth 2.0 redirect error
@@ -77,6 +102,23 @@ let access_token: string
params,
redirect_uri,
code_verifier,
+ {
+ clientPrivateKey,
+ [oauth.useMtlsAlias]: true,
+ // @ts-expect-error
+ [oauth.customFetch]: (...args) => {
+ // @ts-expect-error
+ return undici.fetch(args[0], {
+ ...args[1],
+ dispatcher: new undici.Agent({
+ connect: {
+ key: mtlsClientKey,
+ cert: mtlsClientCertificate,
+ },
+ }),
+ })
+ },
+ },
)
let challenges: oauth.WWWAuthenticateChallenge[] | undefined
@@ -87,7 +129,7 @@ let access_token: string
throw new Error() // Handle WWW-Authenticate Challenges as needed
}
- const result = await oauth.processAuthorizationCodeOAuth2Response(as, client, response)
+ const result = await oauth.processAuthorizationCodeOpenIDResponse(as, client, response)
if (oauth.isOAuth2Error(result)) {
console.error('Error Response', result)
throw new Error() // Handle OAuth 2.0 response body error
@@ -103,6 +145,23 @@ let access_token: string
access_token,
'GET',
new URL('https://rs.example.com/api'),
+ undefined,
+ undefined,
+ {
+ // @ts-expect-error
+ [oauth.customFetch]: (...args) => {
+ // @ts-expect-error
+ return undici.fetch(args[0], {
+ ...args[1],
+ dispatcher: new undici.Agent({
+ connect: {
+ key: mtlsClientKey,
+ cert: mtlsClientCertificate,
+ },
+ }),
+ })
+ },
+ },
)
let challenges: oauth.WWWAuthenticateChallenge[] | undefined