1818 */
1919
2020import Debug from "debug" ;
21- import type { Key , Neo4jAuthorizationSettings } from "../../types" ;
21+ import type { Key , Neo4jAuthorizationSettings , RemoteJWKS } from "../../types" ;
2222
2323import { AUTHORIZATION_UNAUTHENTICATED , DEBUG_AUTH } from "../../constants" ;
2424import { createRemoteJWKSet , decodeJwt , jwtVerify } from "jose" ;
25- import type { JWTPayload } from "jose" ;
25+ import type { JWTPayload , JWTVerifyGetKey } from "jose" ;
2626import { parseBearerToken } from "./parse-request-token" ;
2727import { Neo4jGraphQLError } from "../Error" ;
2828import type { Neo4jGraphQLContext } from "../../types/neo4j-graphql-context" ;
@@ -32,7 +32,18 @@ const debug = Debug(DEBUG_AUTH);
3232export class Neo4jGraphQLAuthorization {
3333 private authorization : Neo4jAuthorizationSettings ;
3434
35+ // Assigned if input is a static symmetric secret or JWKS details
36+ private resolvedKey : Uint8Array | JWTVerifyGetKey | undefined ;
37+ // Assigned if input is dynamic key which needs to be fetched using context details
38+ private unresolvedKey : ( ( context : Neo4jGraphQLContext ) => Key ) | undefined ;
39+
3540 constructor ( authorization : Neo4jAuthorizationSettings ) {
41+ if ( typeof authorization . key === "function" ) {
42+ this . unresolvedKey = authorization . key ;
43+ } else {
44+ this . resolvedKey = this . serializeKey ( authorization . key ) ;
45+ }
46+
3647 this . authorization = authorization ;
3748 }
3849
@@ -62,19 +73,6 @@ export class Neo4jGraphQLAuthorization {
6273 }
6374 }
6475
65- public decodeBearerToken ( bearerToken : string ) : JWTPayload | undefined {
66- const token = parseBearerToken ( bearerToken ) ;
67- if ( ! token ) {
68- throw new Neo4jGraphQLError ( AUTHORIZATION_UNAUTHENTICATED ) ;
69- }
70- try {
71- return decodeJwt ( token ) ;
72- } catch ( error ) {
73- debug ( "%s" , error ) ;
74- throw new Neo4jGraphQLError ( AUTHORIZATION_UNAUTHENTICATED ) ;
75- }
76- }
77-
7876 public async decodeBearerTokenWithVerify ( bearerToken : string | undefined ) : Promise < JWTPayload | undefined > {
7977 if ( ! bearerToken ) {
8078 throw new Neo4jGraphQLError ( AUTHORIZATION_UNAUTHENTICATED ) ;
@@ -89,22 +87,44 @@ export class Neo4jGraphQLAuthorization {
8987 debug ( "Skipping verifying JWT as verify is set to false" ) ;
9088 return decodeJwt ( token ) ;
9189 }
92- return await this . verify ( token , this . authorization . key as Key ) ;
90+ return await this . verifyBearerToken ( token , this . authorization . key as Key ) ;
9391 } catch ( error ) {
9492 debug ( "%s" , error ) ;
9593 throw new Neo4jGraphQLError ( AUTHORIZATION_UNAUTHENTICATED ) ;
9694 }
9795 }
9896
99- private resolveKey ( context : Neo4jGraphQLContext ) : Key {
100- if ( typeof this . authorization . key === "function " ) {
101- return this . authorization . key ( context ) ;
97+ private serializeKey ( key : string | RemoteJWKS ) : Uint8Array | JWTVerifyGetKey {
98+ if ( typeof key === "string " ) {
99+ return Buffer . from ( key ) ;
102100 } else {
103- return this . authorization . key ;
101+ return createRemoteJWKSet ( new URL ( key . url ) , key . options ) ;
104102 }
105103 }
106104
107- private async verify ( token : string , secret : Key ) : Promise < JWTPayload > {
105+ private resolveKey ( context : Neo4jGraphQLContext ) : Uint8Array | JWTVerifyGetKey {
106+ if ( this . resolvedKey ) {
107+ return this . resolvedKey ;
108+ } else {
109+ // this.unresolvedKey is definitely defined due to typings and if/else
110+ const resolved = this . unresolvedKey ! ( context ) ;
111+
112+ return this . serializeKey ( resolved ) ;
113+ }
114+ }
115+
116+ private async verify ( token : string , secret : Uint8Array | JWTVerifyGetKey ) : Promise < JWTPayload > {
117+ if ( secret instanceof Uint8Array ) {
118+ debug ( "Verifying JWT using secret" ) ;
119+ const { payload } = await jwtVerify ( token , secret , this . authorization . verifyOptions ) ;
120+ return payload ;
121+ }
122+ debug ( "Verifying JWKS using url" ) ;
123+ const { payload } = await jwtVerify ( token , secret , this . authorization . verifyOptions ) ;
124+ return payload ;
125+ }
126+
127+ private async verifyBearerToken ( token : string , secret : Key ) : Promise < JWTPayload > {
108128 if ( typeof secret === "string" ) {
109129 debug ( "Verifying JWT using secret" ) ;
110130 const { payload } = await jwtVerify ( token , Buffer . from ( secret ) , this . authorization . verifyOptions ) ;
0 commit comments