Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
node_modules
dist/
lib/
*.tgz
*.tgz
.yarn/
yarn.lock
2 changes: 1 addition & 1 deletion .npmignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,4 @@ tsconfig.json
yarn.lock
.npmignore
rollup.config.js
jest.config.js
jest.config.cjs
1 change: 1 addition & 0 deletions .yarnrc.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
nodeLinker: node-modules
File renamed without changes.
26 changes: 14 additions & 12 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,21 +8,22 @@
"repository": "[email protected]:keratin/authn-node.git",
"author": "Lance Ivy <[email protected]>",
"license": "LGPL-3.0-only",
"type": "module",
"devDependencies": {
"@types/jest": "^27.0.2",
"@types/jsonwebtoken": "^8.5.5",
"@types/node-rsa": "^1.1.1",
"jest": "^27.2.5",
"@types/jest": "^29.5.12",
"@types/jsonwebtoken": "^9.0.6",
"@types/node-rsa": "^1.1.4",
"jest": "^29.7.0",
"node-rsa": "^1.1.1",
"prettier": "^2.4.1",
"rollup": "^2.58.0",
"ts-jest": "^27.0.7",
"typescript": "^4.4.4"
"prettier": "^3.2.5",
"rollup": "^4.13.0",
"ts-jest": "^29.1.2",
"typescript": "^5.4.3"
},
"dependencies": {
"axios": "^0.21.1",
"jsonwebtoken": "^8.5.1",
"jwks-rsa": "^1.12.1"
"axios": "^1.6.8",
"jsonwebtoken": "^9.0.2",
"jwks-rsa": "^3.1.0"
},
"scripts": {
"build": "yarn tsc && rollup -c && cp lib/*.d.ts dist",
Expand All @@ -31,5 +32,6 @@
"problems": "yarn tsc --noEmit && yarn lint:format",
"release": "yarn problems && yarn test && yarn build && git push && yarn publish --access public && git push --tags",
"test": "jest"
}
},
"packageManager": "[email protected]"
}
4 changes: 2 additions & 2 deletions src/Client.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import TokenVerifier, { VerifyToken } from "./TokenVerifier";
import Keychain from "./Keychain";
import TokenVerifier, { VerifyToken } from "./TokenVerifier.js";
import Keychain from "./Keychain.js";
import axios, { AxiosRequestConfig } from "axios";

interface ClientConfig {
Expand Down
2 changes: 1 addition & 1 deletion src/Keychain.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ const Keychain = (config: Config): GetKey => {
return async (header) =>
await new Promise((resolve, reject) => {
client.getSigningKey(header.kid || "unknown", function (err, key) {
err ? reject(err) : resolve(key.getPublicKey());
err ? reject(err) : resolve(key ? key.getPublicKey(): "");
});
});
};
Expand Down
21 changes: 15 additions & 6 deletions src/TokenVerifier.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { JsonWebTokenError, sign } from "jsonwebtoken";
import Key from "node-rsa";

describe("TokenVerifier", () => {
const key = new Key({ b: 512 });
const key = new Key({ b: 2048 });
const verifier = TokenVerifier({
issuer: "authn.example.com",
audiences: ["myapp.example.com"],
Expand Down Expand Up @@ -34,14 +34,14 @@ describe("TokenVerifier", () => {
});

test("with unsigned JWT", async () => {
const token = jwt(key, {}, "none");
const token = jwt(null, {}, "none");
await expect(verifier(token)).rejects.toEqual(
new JsonWebTokenError("jwt signature is required")
);
});

test("with JWT signed by unknown keypair", async () => {
const unknownKey = new Key({ b: 512 });
const unknownKey = new Key({ b: 2048 });
const token = jwt(unknownKey);
await expect(verifier(token)).rejects.toEqual(
new JsonWebTokenError("invalid signature")
Expand Down Expand Up @@ -90,13 +90,22 @@ describe("TokenVerifier", () => {
});

test("with tampered alg=hmac JWT", async () => {
const token = jwt(key, {}, "HS256");
const token = jwt(makeString(2048), {}, "HS256");
await expect(verifier(token)).rejects.toEqual(
new JsonWebTokenError("invalid algorithm")
);
});
});

const makeString = (len: number): string => {
let outString: string = '';
let inOptions: string = 'abcdefghijklmnopqrstuvwxyz0123456789';
for (let i = 0; i < len; i++) {
outString += inOptions.charAt(Math.floor(Math.random() * inOptions.length));
}
return outString;
}

const secondsFromNow = (seconds: number): number =>
Math.floor(Date.now() / 1000) + seconds * 60;

Expand All @@ -109,7 +118,7 @@ interface Claims {
}

const jwt = (
key: Key,
key: Key | string | null,
claims: Partial<Claims> = {},
algorithm: "RS256" | "HS256" | "none" = "RS256"
): string =>
Expand All @@ -122,7 +131,7 @@ const jwt = (
iat: secondsFromNow(-60),
...claims,
},
key.exportKey("pkcs1-private-pem"),
(key && key instanceof Key) ? key.exportKey("pkcs1-private-pem"): (!key ? "": key),
{ algorithm }
);

Expand Down
2 changes: 1 addition & 1 deletion src/TokenVerifier.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { verify } from "jsonwebtoken";
import { GetKey } from "./Keychain";
import { GetKey } from "./Keychain.js";

interface Config {
issuer: string;
Expand Down
2 changes: 1 addition & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
import AuthN from "./Client";
import AuthN from "./Client.js";
export { AuthN };
export { JsonWebTokenError } from "jsonwebtoken";
13 changes: 9 additions & 4 deletions tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
{
"compilerOptions": {
"module": "es2015",
"moduleResolution": "node",
"target": "es6",
"module": "NodeNext",
"moduleResolution": "NodeNext",
"target": "es2022",
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"sourceMap": true,
Expand All @@ -11,11 +11,16 @@

/* checks */
"strict": true,
"skipLibCheck": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true,
"forceConsistentCasingInFileNames": true
},
"include": ["src/**/*"]
"include": ["src/**/*"],
"exclude": [
"src/**/*.spec.ts",
"src/**/*.test.ts"
]
}