Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add web compatibility #60

Merged
merged 81 commits into from
Mar 29, 2022
Merged
Show file tree
Hide file tree
Changes from 76 commits
Commits
Show all changes
81 commits
Select commit Hold shift + click to select a range
7f56f1c
A stab at web compatibility
ottokruse Feb 11, 2022
14409d8
Rely on URL global
ottokruse Feb 21, 2022
9a754f4
Separate https for web and node
ottokruse Feb 21, 2022
5f0f6d4
Node web compat
ottokruse Feb 21, 2022
85cf28f
Ending newline
ottokruse Feb 21, 2022
a2f145a
Tweaked comment
ottokruse Feb 21, 2022
43bc338
Tweaks to package locks
ottokruse Feb 21, 2022
93c197c
One more Buffer removed
ottokruse Feb 21, 2022
e06a590
tweak
ottokruse Feb 21, 2022
5ddae7e
Merge branch 'main' of github.com:awslabs/aws-jwt-verify into web-compat
ottokruse Feb 24, 2022
8060865
Fixes and simplified
ottokruse Feb 24, 2022
6bc1aa5
Fix verify call in web
ottokruse Feb 24, 2022
97fc706
Tweaks for web
ottokruse Feb 25, 2022
04ab8ba
Typing tweaks
ottokruse Feb 25, 2022
dc6ac15
Fix base64 padding handling
ottokruse Feb 25, 2022
18b51c4
Added browser field to . export
ottokruse Feb 25, 2022
d07b4cb
Prettier
ottokruse Feb 25, 2022
e5a8de6
Type tweak
ottokruse Feb 25, 2022
4564a2a
Add coverage
ottokruse Feb 25, 2022
8591c23
Fixed coverage reporting
ottokruse Feb 25, 2022
b2ffd7c
Tweaks
ottokruse Feb 25, 2022
79bbd80
Tweak comment
ottokruse Feb 25, 2022
a295abe
Add comment
ottokruse Feb 25, 2022
7eb1426
browser test for web compat
hakanson Feb 27, 2022
d04f2e7
No seperate bundle for web, but use subpath imports
ottokruse Mar 1, 2022
43b24af
Rename utf8StringFromB64String
ottokruse Mar 1, 2022
0297281
Docs and tweaks to simplify
ottokruse Mar 1, 2022
0f78c49
Comment tweaks
ottokruse Mar 1, 2022
4a74a5d
browser test for web compat
hakanson Feb 27, 2022
675657e
run prettier
hakanson Mar 2, 2022
b6ebfc1
run prettier
hakanson Mar 2, 2022
4f7a90e
Make https fetch equivalent across Node.js and Web (except default re…
ottokruse Mar 2, 2022
211769c
Delete .gitignore
ottokruse Mar 2, 2022
dcc2c2c
Remove esbuild dep
ottokruse Mar 2, 2022
82da002
Merge branch 'web-compat' of github.com:ottokruse/aws-jwt-verify into…
ottokruse Mar 2, 2022
5622b52
Merge branch 'web-compat' into web-compat-vite
ottokruse Mar 2, 2022
8450153
Merge branch 'web-compat' of github.com:ottokruse/aws-jwt-verify into…
hakanson Mar 2, 2022
ab740ea
Fixed bugs (unref and imports)
ottokruse Mar 2, 2022
f9cbb2c
Fix test
ottokruse Mar 2, 2022
9ec001c
Tweak doc
ottokruse Mar 2, 2022
b13d10e
Merge changes
hakanson Mar 2, 2022
8b4ccc0
Rollup fix with alias
ottokruse Mar 3, 2022
57a4d40
Fixed bugs (unref and imports)
ottokruse Mar 2, 2022
5570744
Organize code tweaks
ottokruse Mar 3, 2022
aebbc1c
Doc updates for Web
ottokruse Mar 3, 2022
3b0b42c
Merge branch 'web-compat' into web-compat-vite
ottokruse Mar 3, 2022
7404030
setTimeout unref only in Node.js
ottokruse Mar 3, 2022
fc98d9f
Merge branch 'web-compat' into web-compat-vite
ottokruse Mar 3, 2022
c739808
Fix lint error
ottokruse Mar 3, 2022
045792b
Cleanup
ottokruse Mar 3, 2022
54c8a10
fix typo on VAILD_TOKEN
hakanson Mar 3, 2022
0c25c4d
remove favicon
hakanson Mar 3, 2022
433ca25
Use rollup node resolve
ottokruse Mar 3, 2022
ce2240e
Merge branch 'web-compat-vite' of github.com:hakanson/aws-jwt-verify …
ottokruse Mar 3, 2022
65a2584
remove node-jose
hakanson Mar 4, 2022
da65e7a
update tests
hakanson Mar 4, 2022
ac9b9ca
First stab at run-tests.sh
ottokruse Mar 4, 2022
37101d9
Move B64URL stuff and trim leading zero to test-util
ottokruse Mar 4, 2022
b417475
Remove jwt and jwks sample data from git
ottokruse Mar 7, 2022
8e4011b
Consolidated test util script
ottokruse Mar 7, 2022
7e513cf
gitignore tweak
ottokruse Mar 7, 2022
9cc5a4f
fix tokengen to create directories
hakanson Mar 7, 2022
bdc16ba
add vite preview server testing
hakanson Mar 7, 2022
44bf5cd
Created shell function
ottokruse Mar 7, 2022
dd6eeda
update vite-app README
hakanson Mar 7, 2022
74f8053
Merge branch 'web-compat' into web-compat-vite
ottokruse Mar 7, 2022
1d1b448
Various tweaks to make running tests from the root of the workspace w…
ottokruse Mar 7, 2022
4975071
Merge pull request #1 from hakanson/web-compat-vite
ottokruse Mar 7, 2022
f42eaf5
Set term
ottokruse Mar 7, 2022
861b2e6
CI fix
ottokruse Mar 8, 2022
20feeb2
CI tweaks
ottokruse Mar 8, 2022
84942c0
Merge branch 'web-compat' of github.com:ottokruse/aws-jwt-verify into…
hakanson Mar 8, 2022
1d222b1
Skip exporting video in CI for now (GitHib actions)
ottokruse Mar 8, 2022
a34a6b1
Make installing the test dist more consistent
ottokruse Mar 9, 2022
e448a25
update README
hakanson Mar 22, 2022
51193d5
Added timeout for server start in Vite tests
ottokruse Mar 22, 2022
33339b8
Consolidated supported algorithms type
ottokruse Mar 23, 2022
91a28b7
update cypress unit tests
hakanson Mar 23, 2022
67f728f
Added inline docs to the keypair object that's used in unit tests
ottokruse Mar 25, 2022
531f0e8
Tweaked inline docs
ottokruse Mar 25, 2022
9267f70
Create setTimeoutUnref in node-web-compat
ottokruse Mar 25, 2022
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 .github/ISSUE_TEMPLATE/bug-report.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@ Please provide a clear and concise description of what the bug is.

**Versions**
Which version of `aws-jwt-verify` are you using?
Which version of Node.js are you using? (Should be at least 14)
Are you using the library in Node.js or in the Web browser?
If Node.js, which version of Node.js are you using? (Should be at least 14)
If Web browser, which web browser and which version of it are you using?
If using TypeScript, which version of TypeScript are you using? (Should be at least 4)

**To Reproduce**
Expand Down
4 changes: 3 additions & 1 deletion .github/ISSUE_TEMPLATE/question.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,7 @@ How can we help you?

**Versions**
Which version of `aws-jwt-verify` are you using?
Which version of Node.js are you using? (Should be at least 14)
Are you using the library in Node.js or in the Web browser?
If Node.js, which version of Node.js are you using? (Should be at least 14)
If Web browser, which web browser and which version of it are you using?
If using TypeScript, which version of TypeScript are you using? (Should be at least 4)
3 changes: 3 additions & 0 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,6 @@ jobs:
npm run pack-for-tests
npm run test:install
npm run test:import
npm run test:browser
env:
CI: "true"
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,15 @@ asn1.d.ts
assert.d.ts
cognito-verifier.d.ts
error.d.ts
https-common.d.ts
https-node.d.ts
https.d.ts
index.d.ts
jwk.d.ts
jwt-model.d.ts
jwt-rsa.d.ts
jwt.d.ts
node-web-compat*.d.ts
safe-json-parse.d.ts
test-util.d.ts
typing-util.d.ts
6 changes: 6 additions & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,25 @@ asn1.d.ts
assert.d.ts
cognito-verifier.d.ts
error.d.ts
https-common.d.ts
https-node.d.ts
https.d.ts
index.d.ts
jwk.d.ts
jwt-model.d.ts
jwt-rsa.d.ts
jwt.d.ts
node-web-compat*.d.ts
safe-json-parse.d.ts
test-util.d.ts
typing-util.d.ts

# compiled js
src/*.js
tests/unit/*.js
tests/util/*.js
tests/installation-and-basic-usage/*.js
tests/cognito/cdk.out/*
tests/import-tests/typescript.js
tests/import-tests/should-not-compile.js
tests/vite-app/util/generateExampleTokens.js
14 changes: 11 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
# AWS JWT Verify

**Node.js** library for **verifying** JWTs signed by **Amazon Cognito**, and any **OIDC-compatible IDP** that signs JWTs with **RS256** / **RS384** / **RS512**.
**JavaScript** library for **verifying** JWTs signed by **Amazon Cognito**, and any **OIDC-compatible IDP** that signs JWTs with **RS256** / **RS384** / **RS512**.

## Installation

`npm install aws-jwt-verify`

Note: this library can be used with Node.js 14 or higher. If used with TypeScript, TypeScript 4 or higher is required.
This library can be used with Node.js 14 or higher. If used with TypeScript, TypeScript 4 or higher is required.

This library can also be used in Web browsers.

## Basic usage

Expand Down Expand Up @@ -58,7 +60,7 @@ See all verify parameters for JWTs from any IDP [here](#jwtrsaverifier-verify-pa
## Philosophy of this library

- Do one thing and do it well. Focus solely on **verifying** JWTs.
- Pure **TypeScript** library that can be used in **Node.js** v14 and above (both CommonJS and ESM supported).
- Pure **TypeScript** library that can be used in **Node.js** v14 and above (both CommonJS and ESM supported), as well in the modern evergreen Web browser.
- Support both **Amazon Cognito** as well as any other **OIDC-compatible IDP** as first class citizen.
- **0** runtime dependencies, batteries included. This library includes all necessary code to validate RS256/RS384/RS512-signed JWTs. E.g. it contains a simple (and pluggable) **HTTP** helper to fetch the **JWKS** from the JWKS URI, and it includes a simple **ASN.1** encoder to transform JWKs into **DER-encoded RSA public keys** (in order to verify JWTs with Node.js native crypto calls).
- Opinionated towards the **best practices** as described by the IETF in [JSON Web Token Best Current Practices](https://tools.ietf.org/id/draft-ietf-oauth-jwt-bcp-02.html#rfc.section.3).
Expand All @@ -75,6 +77,12 @@ This library was specifically designed to be easy to use in:
- [CloudFront Lambda@Edge](https://docs.aws.amazon.com/lambda/latest/dg/lambda-edge.html)
- Node.js APIs, e.g. running in AWS Fargate, that need to verify incoming JWTs

## Usage in the Web browser

Many webdev toolchains (e.g. [CreateReactApp](https://github.com/facebook/create-react-app)) make including `npm` libraries in your web app easy, in which case using this library in your web app should just work.

If you need to bundle this library manually yourself, be aware that this library uses [subpath imports](https://nodejs.org/api/packages.html#subpath-imports), to automatically select the Web crypto implementation when bundling for the browser. This is supported out-of-the-box by [webpack](https://webpack.js.org/) and [esbuild](https://esbuild.github.io/). An example of using this library in a Vite web app, with Cypress tests, is included in this repository [here](tests/vite-app/).
elorzafe marked this conversation as resolved.
Show resolved Hide resolved

## Table of Contents

- [Verifying JWTs from Amazon Cognito](#Verifying-JWTs-from-Amazon-Cognito)
Expand Down
2 changes: 1 addition & 1 deletion jest.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ module.exports = {
preset: "ts-jest",
testEnvironment: "node",
moduleFileExtensions: ["ts", "js"],
collectCoverageFrom: ["src/*.ts"],
collectCoverageFrom: ["src/*.ts", "!src/node-web-compat-web.ts"],
leelalagudu marked this conversation as resolved.
Show resolved Hide resolved
roots: ["src", "tests/unit"],
resolver: "<rootDir>/tests/jest-ts-js-resolver.js",
};
15 changes: 9 additions & 6 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
"cognito-verifier.d.ts",
"dist",
"error.d.ts",
"https-common.d.ts",
"https-node.d.ts",
"https.d.ts",
"index.d.ts",
"jwk.d.ts",
Expand Down Expand Up @@ -89,20 +91,21 @@
"typescript": "^4.4.3"
},
"scripts": {
"dist:cjs": "tsc --module CommonJS --outDir dist/cjs && echo '{\"type\":\"commonjs\"}' > dist/cjs/package.json",
"dist:esm": "tsc --module ES2020 --outDir dist/esm && echo '{\"type\":\"module\"}' > dist/esm/package.json",
"dist:cjs": "tsc --module CommonJS --outDir dist/cjs && echo '{\"type\":\"commonjs\",\"imports\":{\"#node-web-compat\":{\"browser\":\"./node-web-compat-web.js\",\"default\":\"./node-web-compat-node.js\"}}}' > dist/cjs/package.json",
"dist:esm": "tsc --module ES2020 --outDir dist/esm && echo '{\"type\":\"module\",\"imports\":{\"#node-web-compat\":{\"browser\":\"./node-web-compat-web.js\",\"default\":\"./node-web-compat-node.js\"}}}' > dist/esm/package.json",
"dist:types": "tsc --declarationDir . --declaration --emitDeclarationOnly",
"dist": "rm -rf dist && npm run dist:cjs && npm run dist:esm && npm run dist:types",
"lint:check": "eslint . --ignore-path .gitignore --max-warnings 0",
"lint": "eslint . --fix --ignore-path .gitignore --max-warnings 0",
"pack-for-tests": "rm -f 'aws-jwt-verify-?.?.?.tgz' && npm pack && mv aws-jwt-verify-*.tgz aws-jwt-verify.tgz",
"pack-for-tests": "rm -f aws-jwt-verify.tgz 'aws-jwt-verify-?.?.?.tgz' && npm pack && mv aws-jwt-verify-*.tgz aws-jwt-verify.tgz",
"prepack": "npm run dist",
"prettier:check": "prettier --check .",
"prettier": "prettier -w .",
"test:all": "npm run prettier:check && npm run test:unit && npm run test:install && npm run test:import && npm run test:speed && npm run test:cognito",
"test:cognito": "cd tests/cognito && npm run test",
"test:import": "cd tests/import-tests && rm -rf node_modules package-lock.json && npm install && node esm.mjs && node commonjs.cjs && tsc && node typescript.js && COMPILE_ERRORS=$(2>&1 tsc -p tsconfig-should-not-compile.json || true) && ([ \"$COMPILE_ERRORS\" != \"\" ] || (echo \"Ooops I did compile successfully :(\"; false))",
"test:all": "npm run prettier:check && npm run test:unit && npm run test:install && npm run test:import && npm run test:browser && npm run test:cognito && npm run test:speed",
"test:cognito": "cd tests/cognito && npm remove aws-jwt-verify.tgz && npm install --no-save --force --no-package-lock ../../aws-jwt-verify.tgz && npm run test",
"test:import": "cd tests/import-tests && npm remove aws-jwt-verify.tgz && npm install --no-save --force --no-package-lock ../../aws-jwt-verify.tgz && node esm.mjs && node commonjs.cjs && tsc && node typescript.js && COMPILE_ERRORS=$(2>&1 tsc -p tsconfig-should-not-compile.json || true) && ([ \"$COMPILE_ERRORS\" != \"\" ] || (echo \"Ooops I did compile successfully :(\"; false))",
"test:install": "./tests/installation-and-basic-usage/run-tests.sh",
"test:browser": "cd tests/vite-app && npm remove aws-jwt-verify.tgz && npm install --no-save --force --no-package-lock ../../aws-jwt-verify.tgz && ./run-tests.sh",
"test:speed": "jest -t \"speed\"",
"test:unit": "jest --collect-coverage -t \"unit\" --testMatch '**/*.test.ts' --reporters=\"jest-junit\" --reporters=\"default\"",
"test": "npm run test:unit",
Expand Down
20 changes: 11 additions & 9 deletions src/assert.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,12 @@ import { AssertionErrorConstructor, FailedAssertionError } from "./error.js";
* @param expected - The expected value
* @param errorConstructor - Constructor for the concrete error to be thrown
*/
export function assertStringEquals(
export function assertStringEquals<T extends string>(
leelalagudu marked this conversation as resolved.
Show resolved Hide resolved
name: string,
actual: unknown,
expected: string,
expected: T,
errorConstructor: AssertionErrorConstructor = FailedAssertionError
): void {
): asserts actual is T {
if (!actual) {
throw new errorConstructor(
`Missing ${name}. Expected: ${expected}`,
Expand Down Expand Up @@ -53,12 +53,14 @@ export function assertStringEquals(
* @param errorConstructor - Constructor for the concrete error to be thrown
* a string here as well, which will mean an array with just that string
*/
export function assertStringArrayContainsString(
export function assertStringArrayContainsString<
T extends string | Readonly<string[]>
>(
name: string,
actual: unknown,
expected: string | string[],
expected: T,
errorConstructor: AssertionErrorConstructor = FailedAssertionError
): void {
): asserts actual is T extends Readonly<string[]> ? T[number] : T {
if (!actual) {
throw new errorConstructor(
`Missing ${name}. ${expectationMessage(expected)}`,
Expand Down Expand Up @@ -92,9 +94,9 @@ export function assertStringArrayContainsString(
export function assertStringArraysOverlap(
name: string,
actual: unknown,
expected: string | string[],
expected: string | Readonly<string[]>,
errorConstructor: AssertionErrorConstructor = FailedAssertionError
): void {
): asserts actual is string | Readonly<string[]> {
if (!actual) {
throw new errorConstructor(
`Missing ${name}. ${expectationMessage(expected)}`,
Expand Down Expand Up @@ -137,7 +139,7 @@ export function assertStringArraysOverlap(
*
* @param expected - The expected value.
*/
function expectationMessage(expected: string | string[]) {
function expectationMessage(expected: string | Readonly<string[]>) {
if (Array.isArray(expected)) {
if (expected.length > 1) {
return `Expected one of: ${expected.join(", ")}`;
Expand Down
2 changes: 1 addition & 1 deletion src/cognito-verifier.ts
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,7 @@ function validateCognitoJwtFields(
assertStringArrayContainsString(
"Token use",
payload.token_use,
["id", "access"],
["id", "access"] as const,
CognitoJwtInvalidTokenUseError
);
if (options.tokenUse !== null) {
Expand Down
18 changes: 14 additions & 4 deletions src/error.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ export abstract class JwtBaseError extends Error {}
interface AssertionError extends JwtBaseError {
failedAssertion: {
actual: unknown;
expected?: string | string[];
expected?: string | Readonly<string[]>;
};
}

Expand All @@ -25,7 +25,7 @@ export interface AssertionErrorConstructor {
new (
msg: string,
actual: unknown,
expected?: string | string[]
expected?: string | Readonly<string[]>
): AssertionError;
}

Expand All @@ -35,9 +35,13 @@ export interface AssertionErrorConstructor {
export class FailedAssertionError extends JwtBaseError {
failedAssertion: {
actual: unknown;
expected?: string | string[];
expected?: string | Readonly<string[]>;
};
constructor(msg: string, actual: unknown, expected?: string | string[]) {
constructor(
msg: string,
actual: unknown,
expected?: string | Readonly<string[]>
) {
super(msg);
this.failedAssertion = {
actual,
Expand Down Expand Up @@ -139,3 +143,9 @@ export class FetchError extends JwtBaseError {
}

export class NonRetryableFetchError extends FetchError {}

/**
* Web compatibility errors
*/

export class NotSupportedError extends JwtBaseError {}
38 changes: 38 additions & 0 deletions src/https-common.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
//
// Lower-level HTTPS functionalities, common for Node.js and Web

import { FetchError, NonRetryableFetchError } from "./error.js";

/**
* Sanity check a HTTPS response where we expect to get JSON data back
*
* @param uri the uri that was being requested
* @param statusCode the HTTP status code, should be 200
* @param contentType the value of the "Content-Type" header in the response, should start with "application/json"
* @returns void - throws an error if the status code or content type aren't as expected
*/
export function validateHttpsJsonResponse(
uri: string,
statusCode?: number,
contentType?: string
): void {
if (statusCode === 429) {
throw new FetchError(uri, "Too many requests");
} else if (statusCode !== 200) {
throw new NonRetryableFetchError(
uri,
`Status code is ${statusCode}, expected 200`
);
}
if (
!contentType ||
!contentType.toLowerCase().startsWith("application/json")
) {
throw new NonRetryableFetchError(
uri,
`Content-type is "${contentType}", expected "application/json"`
);
}
}
Loading