@@ -29,17 +29,16 @@ npm install jsonwebtoken axios jose
2929
3030``` js
3131const axios = require (' axios' );
32- const jwt = require (' jsonwebtoken' );
33- const { importJWK } = require (' jose' );
32+ const { jwtVerify , importJWK } = require (' jose' );
3433
3534/**
3635 * Verifies:
3736 * 1. session.state === state
3837 * 2. id token is valid
3938 * 3. session.nonce === payload.nonce
40- *
39+ *
4140 * Returns org_id from token if valid
42- *
41+ *
4342 * @param {string} idToken - The id_token from the redirect
4443 * @param {object} session - Contains expected `state` and `nonce`
4544 * @param {string} state - State from the redirect
@@ -52,25 +51,24 @@ async function verifyRedirect(idToken, session, state) {
5251 }
5352
5453 // Step 2: Decode header to get kid
55- const decodedHeader = jwt . decode ( idToken, { complete : true } );
56- if (! decodedHeader? .header ? . kid ) {
54+ const decodedHeader = JSON . parse ( Buffer . from ( idToken . split ( ' . ' )[ 0 ], ' base64 ' ). toString () );
55+ if (! decodedHeader? .kid ) {
5756 throw new Error (' Invalid id token: missing kid' );
5857 }
5958
60- const kid = decodedHeader .header . kid ;
59+ const kid = decodedHeader .kid ;
6160
6261 // Step 3: Fetch JWKS and get matching key
6362 const keys = await fetchAdobeKeys ();
63+
6464 const jwk = keys .find (k => k .kid === kid);
6565 if (! jwk) {
6666 throw new Error (` No matching JWK found for kid: ${ kid} ` );
6767 }
6868
69- // Step 4: Convert to public key
70- const publicKey = await getPublicKeyFromJwk (jwk);
71-
72- // Step 5: Verify id token signature
73- const payload = jwt .verify (idToken, publicKey, {
69+ // Step 4: Import JWK and verify token
70+ const publicKey = await importJWK (jwk, jwk .alg );
71+ const { payload } = await jwtVerify (idToken, publicKey, {
7472 algorithms: [' RS256' ],
7573 });
7674
@@ -80,11 +78,11 @@ async function verifyRedirect(idToken, session, state) {
8078 }
8179
8280 // Step 7: Return org_id
83- if (! payload .org_id ) {
81+ if (! payload .orgId ) {
8482 throw new Error (' org_id claim missing in id_token' );
8583 }
8684
87- return payload .org_id ;
85+ return payload .orgId ;
8886}
8987
9088/**
@@ -95,12 +93,7 @@ async function fetchAdobeKeys() {
9593 return response .data .keys ;
9694}
9795
98- /**
99- * Convert JWK to a usable public key
100- */
101- async function getPublicKeyFromJwk (jwk ) {
102- return await importJWK (jwk, jwk .alg );
103- }
96+
10497
10598// Example usage
10699(async () => {
@@ -137,71 +130,72 @@ from jwt import PyJWKClient
137130
138131ADOBE_JWKS_URL = " https://ims-na1.adobelogin.com/ims/keys"
139132
140- def verify_redirect (id_token: str, session: dict, state: str) - > str:
141- " " "
142- Verifies:
143- 1. session.state == state
144- 2. id token is valid via Adobe public keys
145- 3. session.nonce == token's nonce
146- 4. Returns org_id from the token if all checks pass
147-
148- :param id_token: The id_token returned from the redirect
149- :param session: Dict with 'state' and 'nonce' keys
150- :param state: The 'state' query parameter from redirect
151- :return: org_id claim from the id_token
152- :raises RedirectVerificationError: on any failure
153- " " "
154-
155- # Step 1 : Check state
156- if session .get (' state' ) != state:
157- raise RedirectVerificationError (" State mismatch" )
158-
159- # Step 2 : Load signing key using PyJWKClient
160- try:
161- jwk_client = PyJWKClient (ADOBE_JWKS_URL )
162- signing_key = jwk_client .get_signing_key_from_jwt (id_token)
163- except Exception as e:
164- raise RedirectVerificationError (f" JWK retrieval/lookup failed: {e}" )
165-
166- # Step 3 : Verify id_token signature
167- try:
168- decoded = jwt .decode (
169- id_token,
170- signing_key .key ,
171- algorithms= [" RS256" ]
172- )
173- except jwt .PyJWTError as e:
174- raise RedirectVerificationError (f" id token verification failed: {e}" )
175-
176- # Step 4 : Nonce check
177- if session .get (' nonce' ) != decoded .get (' nonce' ):
178- raise RedirectVerificationError (" Nonce mismatch" )
179-
180- # Step 5 : Return org_id
181- org_id = decoded .get (' org_id' )
182- if not org_id:
183- raise RedirectVerificationError (" org_id claim missing in token" )
184-
185- return org_id
133+ def verify_redirect (id_token: str, session: dict, state: str, client_id: str) - > str:
134+ " " "
135+ Verifies:
136+ 1. session.state == state
137+ 2. id token is valid via Adobe public keys
138+ 3. session.nonce == token's nonce
139+ 4. Returns org_id from the token if all checks pass
140+
141+ :param id_token: The id_token returned from the redirect
142+ :param session: Dict with 'state' and 'nonce' keys
143+ :param state: The 'state' query parameter from redirect
144+ :return: org_id claim from the id_token
145+ :raises RedirectVerificationError: on any failure
146+ " " "
147+
148+ # Step 1 : Check state
149+ if session .get (' state' ) != state:
150+ raise RedirectVerificationError (" State mismatch" )
151+
152+ # Step 2 : Load signing key using PyJWKClient
153+ try:
154+ jwk_client = PyJWKClient (ADOBE_JWKS_URL )
155+ signing_key = jwk_client .get_signing_key_from_jwt (id_token)
156+ except Exception as e:
157+ raise RedirectVerificationError (f" JWK retrieval/lookup failed: {e}" )
158+
159+ # Step 3 : Verify id_token signature
160+ try:
161+ decoded = jwt .decode (
162+ id_token,
163+ signing_key .key ,
164+ audience= client_id,
165+ algorithms= [" RS256" ]
166+ )
167+ except jwt .PyJWTError as e:
168+ raise RedirectVerificationError (f" id token verification failed: {e}" )
169+
170+ # Step 4 : Nonce check
171+ if session .get (' nonce' ) != decoded .get (' nonce' ):
172+ raise RedirectVerificationError (" Nonce mismatch" )
173+
174+ # Step 5 : Return org_id
175+ org_id = decoded .get (' orgId' )
176+ if not org_id:
177+ raise RedirectVerificationError (" orgId claim missing in token" )
178+
179+ return org_id
186180
187181class RedirectVerificationError (Exception):
188- pass
182+ pass
189183
190184# Example usage
191185if __name__ == " __main__" :
192- id_token = " your.id.token.here"
193- session = {
194- " state" : " xyz123" ,
195- " nonce" : " abc456"
196- }
197- state = " xyz123"
198-
199- try :
200- org_id = verify_redirect (id_token, session, state)
201- print ( " Verified org_id: " , org_id )
202- except RedirectVerificationError as e :
203- print ( " Redirect verification failed: " , e)
204-
186+ id_token = " your.id.token.here"
187+ session = {
188+ " state" : " xyz123" ,
189+ " nonce" : " abc456"
190+ }
191+ state = " xyz123"
192+ client_id = " your.application.client.id "
193+
194+ try :
195+ org_id = verify_redirect (id_token, session, state, client_id )
196+ print ( " Verified org_id: " , org_id)
197+ except RedirectVerificationError as e :
198+ print ( " Redirect verification failed: " , e)
205199` ` `
206200
207201## Java
@@ -283,9 +277,9 @@ public class VerifyRedirect {
283277 }
284278
285279 // Step 6: Return org_id
286- String orgId = verifiedJwt .getClaim (" org_id " ).asString ();
280+ String orgId = verifiedJwt .getClaim (" orgId " ).asString ();
287281 if (orgId == null || orgId .isEmpty ()) {
288- throw new Exception (" org_id claim missing in token" );
282+ throw new Exception (" orgId claim missing in token" );
289283 }
290284
291285 return orgId;
0 commit comments