@@ -4,11 +4,11 @@ import {HTTPException} from 'hono/http-exception';
44import type { StatusCode , UnofficialStatusCode } from 'hono/utils/http-status' ;
55import { createMiddleware } from 'hono/factory' ;
66import { ZodType } from 'zod' ;
7- import { createVerifier , KeyFetcher , TokenError , VerifierOptions , } from 'fast-jwt' ;
87import { formatZodIssue , JsonTransformer } from './zod-utils.js' ;
98import { Status , StatusPhrases } from './http-utils.js' ;
10- import { buildJwksKeyFetcher } from './jwt-utils.js' ;
119import { indent } from './common-utils.js' ;
10+ import { createRemoteJWKSet , jwtVerify , JWTVerifyOptions } from 'jose' ;
11+ import { JOSEError } from 'jose/errors' ;
1212
1313/**
1414 * Creates a NotFoundHandler that responses with JSON
@@ -94,14 +94,15 @@ export async function parseJsonBody<T extends ZodType>(req: HonoRequest, schema:
9494
9595/**
9696 * Creates a middleware that verifies a token and sets the token payload as 'token' context variable
97+ * @param jwksUrl - URL of the JWKS
9798 * @param options - fast-jwt createVerifier options
9899 * @return middleware
99100 */
100101export function tokenAuthenticator < T extends object > (
101- options : Partial < VerifierOptions & { key ?: KeyFetcher } > ,
102+ jwksUrl : URL ,
103+ options : JWTVerifyOptions & { subjects ?: RegExp [ ] } ,
102104) {
103- options . key ??= buildJwksKeyFetcher ( { providerDiscovery : true } ) ;
104- const verifier = createVerifier ( options ) ;
105+ const jwkSet = createRemoteJWKSet ( jwksUrl ) ;
105106
106107 return createMiddleware < { Variables : { token : T } } > ( async ( context , next ) => {
107108 const authorizationHeaderValue = context . req . header ( ) . authorization ;
@@ -118,23 +119,25 @@ export function tokenAuthenticator<T extends object>(
118119 } ) ;
119120 }
120121
121- const tokenPayload = await verifier ( tokenValue )
122- . catch ( ( error ) => {
123- console . log ( `FUCK verifier error` , {
124- error : error . message ,
125- code : error . code ,
126- originalError : error . originalError ?. message ,
127- stack : JSON . stringify ( error . originalError ?. stack ) ,
128- } ) ; // TODO remove debug log
129- if ( error instanceof TokenError ) {
130- throw new HTTPException ( Status . UNAUTHORIZED , {
131- message : error . message ,
132- } ) ;
133- }
134- throw error ;
122+ const token = await jwtVerify ( tokenValue ,
123+ jwkSet , options ,
124+ ) . catch ( ( error ) => {
125+ if ( error instanceof JOSEError ) {
126+ throw new HTTPException ( Status . UNAUTHORIZED , {
127+ message : 'Invalid token: ' + error . message ,
135128 } ) ;
129+ }
130+ throw error ;
131+ } ) ;
132+
133+ if ( options . subjects && ! options . subjects
134+ . some ( ( subject ) => subject . test ( token . payload . sub ?? '' ) ) ) {
135+ throw new HTTPException ( Status . UNAUTHORIZED , {
136+ message : `Invalid Token: unexpected "sub" claim value` ,
137+ } ) ;
138+ }
136139
137- context . set ( 'token' , tokenPayload as T ) ;
140+ context . set ( 'token' , token . payload as T ) ;
138141
139142 await next ( ) ;
140143 } ) ;
0 commit comments