@neo4j/graphql-plugin-auth
Advanced tools
Comparing version 2.0.0 to 2.1.0
@@ -0,4 +1,6 @@ | ||
import type JwksRsa from "jwks-rsa"; | ||
import { JwksClient } from "jwks-rsa"; | ||
import type { RequestLike } from "./types"; | ||
export interface JWKSPluginInput { | ||
jwksEndpoint: string; | ||
jwksEndpoint: string | ((req: RequestLike) => string); | ||
rolesPath?: string; | ||
@@ -11,5 +13,8 @@ globalAuthentication?: boolean; | ||
isGlobalAuthenticationEnabled?: boolean; | ||
client: JwksClient; | ||
client: JwksClient | null; | ||
options: JwksRsa.Options; | ||
bindPredicate: "all" | "any"; | ||
input: JWKSPluginInput; | ||
constructor(input: JWKSPluginInput); | ||
tryToResolveKeys(req: RequestLike): void; | ||
decode<T>(token: string): Promise<T | undefined>; | ||
@@ -16,0 +21,0 @@ private verifyJWKS; |
@@ -31,7 +31,13 @@ "use strict"; | ||
constructor(input) { | ||
this.client = null; | ||
//We are going to use this input later, so we need to save it here. | ||
this.input = input; | ||
this.rolesPath = input.rolesPath; | ||
this.isGlobalAuthenticationEnabled = input.globalAuthentication || false; | ||
this.bindPredicate = input.bindPredicate || "all"; | ||
const options = { | ||
jwksUri: input.jwksEndpoint, | ||
//It will be empty string if the endpoint is a function | ||
//This means the value will be calculated later | ||
const jwksEndpoint = typeof input.jwksEndpoint === "string" ? input.jwksEndpoint : ""; | ||
this.options = { | ||
jwksUri: jwksEndpoint, | ||
rateLimit: true, | ||
@@ -43,4 +49,14 @@ jwksRequestsPerMinute: 10, | ||
}; | ||
this.client = new jwks_rsa_1.JwksClient(options); | ||
//If the endpoint is set in the constructor directly we can create th client immediately here | ||
if (jwksEndpoint !== "") | ||
this.client = new jwks_rsa_1.JwksClient(this.options); | ||
} | ||
tryToResolveKeys(req) { | ||
if (typeof this.input.jwksEndpoint === "string") | ||
return; | ||
//The url will be computed based on the jwksEndpoint implementation | ||
this.options.jwksUri = this.input.jwksEndpoint(req); | ||
this.client = new jwks_rsa_1.JwksClient(this.options); | ||
return; | ||
} | ||
async decode(token) { | ||
@@ -61,2 +77,6 @@ let result; | ||
const getKey = (header, callback) => { | ||
if (!this.client) { | ||
debug("JwksClient should NOT be empty! Make sure the 'tryToResolveKeys' method is called before decoding"); | ||
return; | ||
} | ||
const kid = header.kid || ""; | ||
@@ -69,2 +89,4 @@ this.client.getSigningKey(kid, (err, key) => { | ||
return new Promise((resolve, reject) => { | ||
if (!this.client) | ||
reject("JwksClient should not be empty! Make sure the 'tryToResolveKeys' method is called before decoding"); | ||
jsonwebtoken_1.default.verify(token, getKey, { | ||
@@ -71,0 +93,0 @@ algorithms: ["HS256", "RS256"], |
import jsonwebtoken from "jsonwebtoken"; | ||
import type { RequestLike } from "./types"; | ||
export interface JWTPluginInput { | ||
secret: jsonwebtoken.Secret; | ||
secret: jsonwebtoken.Secret | ((req: RequestLike) => jsonwebtoken.Secret); | ||
noVerify?: boolean; | ||
@@ -14,4 +15,6 @@ globalAuthentication?: boolean; | ||
isGlobalAuthenticationEnabled?: boolean; | ||
input: JWTPluginInput; | ||
bindPredicate: "all" | "any"; | ||
constructor(input: JWTPluginInput); | ||
tryToResolveKeys(req: RequestLike): void; | ||
decode<T>(token: string): Promise<T | undefined>; | ||
@@ -18,0 +21,0 @@ } |
@@ -27,6 +27,9 @@ "use strict"; | ||
const constants_1 = require("./constants"); | ||
const exceptions_1 = require("./exceptions"); | ||
const debug = (0, debug_1.default)(constants_1.DEBUG_PREFIX); | ||
class Neo4jGraphQLAuthJWTPlugin { | ||
constructor(input) { | ||
this.secret = input.secret; | ||
this.secret = null; | ||
this.input = input; | ||
this.secret = typeof input.secret === "function" ? null : input.secret; | ||
this.noVerify = input.noVerify; | ||
@@ -40,2 +43,8 @@ this.rolesPath = input.rolesPath; | ||
} | ||
tryToResolveKeys(req) { | ||
if (typeof this.input.secret !== "function") | ||
return; | ||
this.secret = this.input.secret(req); | ||
return; | ||
} | ||
/* eslint-disable @typescript-eslint/require-await */ | ||
@@ -55,5 +64,12 @@ async decode(token) { | ||
} | ||
else if (typeof this.input.secret === "function" && !this.secret) { | ||
debug("'secret' should not be null, make sure the 'tryToResolveKeys' is ran before the decode method."); | ||
throw exceptions_1.AUTH_JWT_PLUGIN_NULL_SECRET_EXCEPTION; | ||
} | ||
} | ||
catch (error) { | ||
debug("%s", error); | ||
if (error === exceptions_1.AUTH_JWT_PLUGIN_NULL_SECRET_EXCEPTION) { | ||
throw error; | ||
} | ||
} | ||
@@ -60,0 +76,0 @@ return result; |
{ | ||
"name": "@neo4j/graphql-plugin-auth", | ||
"version": "2.0.0", | ||
"version": "2.1.0", | ||
"description": "Auth decode plugins for @neo4j/graphql", | ||
@@ -38,9 +38,9 @@ "keywords": [ | ||
"@types/debug": "4.1.7", | ||
"@types/jest": "29.2.5", | ||
"@types/jsonwebtoken": "9.0.0", | ||
"@types/jest": "29.2.6", | ||
"@types/jsonwebtoken": "9.0.1", | ||
"@types/node": "18.11.17", | ||
"jest": "29.3.1", | ||
"ts-jest": "29.0.4", | ||
"ts-jest": "29.0.5", | ||
"typescript": "4.9.4" | ||
} | ||
} |
@@ -29,2 +29,15 @@ # @neo4j/graphql-plugin-auth | ||
}); | ||
// Or you can initiate the secret with a function which will run to retrieve the secret when the request comes in | ||
const neoSchema = new Neo4jGraphQL({ | ||
typeDefs, | ||
plugins: { | ||
auth: new Neo4jGraphQLAuthJWTPlugin({ | ||
secret: (req) => { | ||
return "super-secret"; | ||
}, | ||
}), | ||
}, | ||
}); | ||
``` | ||
@@ -46,2 +59,18 @@ | ||
}); | ||
//Or you can pass a function as jskwsEndpoint to compute the endpoint when the request comes in. | ||
const neoSchema = new Neo4jGraphQL({ | ||
typeDefs, | ||
plugins: { | ||
auth: new Neo4jGraphQLAuthJWKSPlugin({ | ||
jwksEndpoint: (req) => { | ||
let url = "https://YOUR_DOMAIN/well-known/{file}.json"; | ||
const fileHeader = req.headers["file"]; | ||
url = url.replace("{file}", fileHeader); | ||
return url; | ||
}, | ||
}), | ||
}, | ||
}); | ||
``` | ||
@@ -48,0 +77,0 @@ |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
33667
27
289
79