@@ -6,13 +6,16 @@ import {
66 mockJwt ,
77 mockJwtHeader ,
88 mockJwtPayload ,
9+ mockM2MJwtPayload ,
910 mockOAuthAccessTokenJwtPayload ,
1011 pemEncodedPublicKey ,
12+ pemEncodedSignKey ,
1113 publicJwks ,
1214 signedJwt ,
1315 someOtherPublicKey ,
1416} from '../../fixtures' ;
1517import { mockSignedOAuthAccessTokenJwt , mockSignedOAuthAccessTokenJwtApplicationTyp } from '../../fixtures/machine' ;
18+ import { signJwt } from '../signJwt' ;
1619import { decodeJwt , hasValidSignature , verifyJwt } from '../verifyJwt' ;
1720
1821const invalidTokenError = {
@@ -234,6 +237,50 @@ describe('verifyJwt(jwt, options)', () => {
234237 expect ( error ?. message ) . toContain ( 'Expected "at+jwt, application/at+jwt"' ) ;
235238 } ) ;
236239
240+ it ( 'verifies JWT when array aud includes the configured audience' , async ( ) => {
241+ const audience = 'https://my-resource.example.com' ;
242+ const { data : jwtWithArrayAud } = await signJwt (
243+ {
244+ ...mockM2MJwtPayload ,
245+ aud : [ 'https://other-resource.example.com' , audience ] ,
246+ } ,
247+ pemEncodedSignKey ,
248+ {
249+ algorithm : mockJwtHeader . alg ,
250+ header : mockJwtHeader ,
251+ } ,
252+ ) ;
253+
254+ const { data } = await verifyJwt ( jwtWithArrayAud || '' , {
255+ key : pemEncodedPublicKey ,
256+ audience,
257+ } ) ;
258+
259+ expect ( data ?. aud ) . toEqual ( [ 'https://other-resource.example.com' , audience ] ) ;
260+ } ) ;
261+
262+ it ( 'rejects JWT when array aud does not include the configured audience' , async ( ) => {
263+ const { data : jwtWithArrayAud } = await signJwt (
264+ {
265+ ...mockM2MJwtPayload ,
266+ aud : [ 'https://attacker.example.com' ] ,
267+ } ,
268+ pemEncodedSignKey ,
269+ {
270+ algorithm : mockJwtHeader . alg ,
271+ header : mockJwtHeader ,
272+ } ,
273+ ) ;
274+
275+ const { errors : [ error ] = [ ] } = await verifyJwt ( jwtWithArrayAud || '' , {
276+ key : pemEncodedPublicKey ,
277+ audience : 'https://my-resource.example.com' ,
278+ } ) ;
279+
280+ expect ( error ) . toBeDefined ( ) ;
281+ expect ( error ?. message ) . toContain ( 'Invalid JWT audience claim array' ) ;
282+ } ) ;
283+
237284 it ( 'rejects an expired JWT when clockSkewInMs is explicitly 0' , async ( ) => {
238285 vi . setSystemTime ( new Date ( ( mockJwtPayload . exp + 1 ) * 1000 ) ) ;
239286 const inputVerifyJwtOptions = {
0 commit comments