1
1
/* eslint-disable @typescript-eslint/ban-ts-comment */
2
2
import { vi } from 'vitest'
3
- import { encodeBase64 } from '../encode'
3
+ import { encodeBase64 , encodeBase64Url } from '../encode'
4
4
import { AlgorithmTypes } from './jwa'
5
+ import { signing } from './jws'
5
6
import * as JWT from './jwt'
7
+ import { verifyFromJwks } from './jwt'
6
8
import {
7
9
JwtAlgorithmNotImplemented ,
8
10
JwtTokenExpired ,
@@ -11,6 +13,7 @@ import {
11
13
JwtTokenNotBefore ,
12
14
JwtTokenSignatureMismatched ,
13
15
} from './types'
16
+ import { utf8Encoder } from './utf8'
14
17
15
18
describe ( 'isTokenHeader' , ( ) => {
16
19
it ( 'should return true for valid TokenHeader' , ( ) => {
@@ -474,6 +477,45 @@ describe('JWT', () => {
474
477
} )
475
478
} )
476
479
480
+ describe ( 'verifyFromJwks header.alg fallback' , ( ) => {
481
+ it ( 'Should use header.alg as fallback when matchingKey.alg is missing' , async ( ) => {
482
+ // Setup: Create a JWT signed with HS384 (different from default HS256)
483
+ const payload = { message : 'hello world' }
484
+ const headerAlg = 'HS384' // Non-default value
485
+ const secret = 'secret'
486
+ const kid = 'dummy'
487
+
488
+ // Create JWT (signed with HS384)
489
+ const header = { alg : headerAlg , typ : 'JWT' , kid }
490
+ const encode = ( obj : object ) => encodeBase64Url ( utf8Encoder . encode ( JSON . stringify ( obj ) ) . buffer )
491
+ const encodedHeader = encode ( header )
492
+ const encodedPayload = encode ( payload )
493
+ const signingInput = `${ encodedHeader } .${ encodedPayload } `
494
+
495
+ // Use signing function from jws.ts instead of createHmac directly
496
+ const signatureBuffer = await signing ( secret , headerAlg , utf8Encoder . encode ( signingInput ) )
497
+ const signature = encodeBase64Url ( signatureBuffer )
498
+
499
+ const token = `${ encodedHeader } .${ encodedPayload } .${ signature } `
500
+
501
+ // Create a key without alg property
502
+ const keys = [
503
+ {
504
+ kty : 'oct' ,
505
+ kid,
506
+ k : encodeBase64Url ( utf8Encoder . encode ( secret ) . buffer ) ,
507
+ use : 'sig' ,
508
+ // alg is intentionally omitted
509
+ } ,
510
+ ]
511
+
512
+ // Execute: Verify the JWT token signed with HS384
513
+ const result = await verifyFromJwks ( token , { keys } )
514
+
515
+ // If verification succeeds, it means header.alg was used
516
+ expect ( result ) . toEqual ( payload )
517
+ } )
518
+ } )
477
519
async function exportPEMPrivateKey ( key : CryptoKey ) : Promise < string > {
478
520
const exported = await crypto . subtle . exportKey ( 'pkcs8' , key )
479
521
const pem = `-----BEGIN PRIVATE KEY-----\n${ encodeBase64 ( exported ) } \n-----END PRIVATE KEY-----`
0 commit comments