Skip to content

Commit

Permalink
more tests
Browse files Browse the repository at this point in the history
  • Loading branch information
Pinta365 committed Apr 9, 2024
1 parent d329ac7 commit db6fab8
Show file tree
Hide file tree
Showing 8 changed files with 363 additions and 129 deletions.
11 changes: 9 additions & 2 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,12 @@ jobs:
uses: cross-org/workflows/.github/workflows/deno-ci.yml@main
with:
entrypoint: mod.ts
run_tests: false
lint_docs: false
bun_ci:
uses: cross-org/workflows/.github/workflows/bun-ci.yml@main
with:
jsr_dependencies: "@cross/deepmerge @cross/fs @cross/test @std/assert @std/encoding"
node_ci:
uses: cross-org/workflows/.github/workflows/node-ci.yml@main
with:
jsr_dependencies: "@cross/deepmerge @cross/fs @cross/test @std/assert @std/encoding"
test_target: "*.test.ts"
71 changes: 67 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,19 +32,79 @@ npx jsr add @cross/jwt

See [docs on jsr.io](https://jsr.io/@cross/jwt/doc) for details.

**Sign and validate**

- **`signJWT(payload: JWTPayload, key: CryptoKey | string | false, options?: JWTOptions): Promise<string>`**

```javascript
// Create and sign a JWT from a string directly, uses a HS256 key by default.
const jwt = await signJWT({ hello: "world" }, "mySuperSecretAtLeast32CharsLong!");

// Create and sign a JWT from a string directly, using a HS512 algorithm.
const jwt = await signJWT({ hello: "world" }, "Secret my Super Secret at least 64 bytes long for HS512 algorithm!!!!", {
algorithm: "HS512",
});

// Create and sign a JWT from a CryptoKey (secret based or private key), and opting out of writing IAT claim when signing.
// Using a cryptokey the library will parse algorithm from the supplied key
const jwt = await signJWT({ hello: "world" }, cryptoKey, { setIat: false });

// Create a JWT without signing it, essentially an unsecure JWT.
const jwt = await signJWT({ hello: "world" }, false);
```

- **`validateJWT(jwt: string, key: CryptoKey | string | false, options?: JWTOptions): Promise<JWTPayload>`**

```javascript
// Validate and parse JWT with a string secret directly, uses a HS256 key by default.
const data = await validateJWT(jwt, "mySuperSecretAtLeast32CharsLong!");

// Validate and parse JWT with a string secret directly, uses a HS256 key by default.
const data = await validateJWT(jwt, "Secret my Super Secret at least 64 bytes long for HS512 algorithm!!!!", {
algorithm: "HS512",
});

// Validate and parse JWT with a CryptoKey (secret based or public key).
// Using a cryptokey the library will parse algorithm from the supplied key.
const data = await validateJWT(jwt, cryptoKey);

// Parsing a unsecure JWT
const data = await validateJWT(jwt, false);
```

**Helper Functions**

- **`generateKey(keyStr: string, optionsOrAlgorithm?: SupportedGenerateKeyAlgorithms | Options): Promise<CryptoKey>`**

```javascript
// Generates a HS256 key by default
const key = await generateKey(stringSecret);

// Generates a HS512 key
const key = await generateKey(stringSecret, "HS512");

// Generates a HS256 key by using options object (see GenerateKeyOptions)
const key = await generateKey(stringSecret, { algorithm: "HS512" });
```

- **`generateKeyPair(optionsOrAlgorithm?: KeyPairOptions): Promise<CryptoKeyPair>`**

- **`exportKeyFiles(options: exportKeyFilesOptions): Promise<ExportedKeyFiles>`** (Experimental)
```javascript
// Generates a RS256 key pair by default.
const { privateKey, publicKey } = await generateKeyPair();

**Sign and validate**
// Generates a HS512 key pair.
const { privateKey, publicKey } = await generateKeyPair("RS512");

// Generates a HS512 key pair by using options object (see GenerateKeyPairOptions).
const key = await generateKeyPair({ algorithm: "HS512" });
```

- **`signJWT(payload: JWTPayload, key: CryptoKey | string, options?: Options): Promise<string>`**
- **`exportKeyFiles(options: exportKeyFilesOptions): Promise<ExportedKeyFiles>`** (Experimental)

- **`validateJWT(jwt: string, key: CryptoKey | string, options?: Options): Promise<JWTPayload>`**
```javascript
// Experimental, no examples.
```

**GenerateKeyOptions Object**

Expand Down Expand Up @@ -76,6 +136,9 @@ interface GenerateKeyPairOptions {
// The desired length of the RSA modulus in bits. Larger values offer greater
// security, but impact performance. A common default is 2048.
modulusLength?: number;
// If true, allows generation of key pairs with modulus length shorter than recommended security guidelines.
// Use with caution, as shorter lengths are less secure.
allowInsecureModulusLengths?: boolean;
}
```

Expand Down
2 changes: 1 addition & 1 deletion deno.jsonc
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@cross/jwt",
"version": "0.4.0",
"version": "0.4.1",
"exports": "./mod.ts",

"tasks": {
Expand Down
51 changes: 43 additions & 8 deletions mod.test.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { assertEquals } from "@std/assert";
import { assertEquals, assertRejects } from "@std/assert";
import { test } from "@cross/test";
import { generateKey, generateKeyPair, signJWT, validateJWT } from "./mod.ts";
import { JWTFormatError, JWTValidationError } from "./src/error.ts";
import type { SupportedGenerateKeyAlgorithms, SupportedGenerateKeyPairAlgorithms } from "./src/cryptokeys.ts";

/** ==== Signing and Verification ==== */
test("signJWT() and validateJWT() with HMAC algorithms", async () => {
for (const algorithm of ["HS256", "HS384", "HS512"]) {
const secret =
Expand Down Expand Up @@ -45,12 +45,47 @@ test("signJWT() and validateJWT() with RSA-PPS algorithms", async () => {
assertEquals(decodedPayload.foo, payload.foo);
}
});
/*
More tests to come.
test("validateJWT() fails with incorrect key", async () => {

test("validateJWT() throws JWTFormatError on invalid jwt structure", async () => {
const secret = "mySuperSecretAtLeast32CharsLong!";
const payload = { foo: "bar" };
let jwtString = await signJWT(payload, secret);

// Add extra period
jwtString += ".extraPart";
await assertRejects(() => validateJWT(jwtString, secret), JWTFormatError);
});

test("validateJWT() throws JWTValidationError on incorrect key", async () => {
const secret = "mySuperSecretAtLeast32CharsLong!";
const jwtString = await signJWT({ foo: "bar" }, secret);

await assertRejects(
() => validateJWT(jwtString, "incorrect_keyincorrect_keyincorrect_keyincorrect_key"),
JWTValidationError,
);
});

test("validateJWT() throws JWTFormatError on invalid Base64URL", async () => {
const secret = "mySuperSecretAtLeast32CharsLong!";
const payload = { foo: "bar" };
let jwtString = await signJWT(payload, secret);
const parts = jwtString.split(".");

// Tamper with the header
const tamperedHeader = parts[0] + "A";
jwtString = [tamperedHeader, parts[1], parts[2]].join(".");
await assertRejects(() => validateJWT(jwtString, secret), JWTFormatError);
});

test("validateJWT() throws JWTValidationError on tampered payload ", async () => {
const secret = "mySuperSecretAtLeast32CharsLong!";
const jwtString = await signJWT({ hello: "world" }, secret);
const payload = { foo: "bar" };
let jwtString = await signJWT(payload, secret);
const parts = jwtString.split(".");

assertThrows(async () => await validateJWT(jwtString, "incorrect_keyincorrect_keyincorrect_keyincorrect_key"));
// Tamper with the payload
const tamperedPayload = parts[1].slice(0, -2);
jwtString = [parts[0], tamperedPayload, parts[2]].join(".");
await assertRejects(() => validateJWT(jwtString, secret), JWTValidationError);
});
*/
12 changes: 11 additions & 1 deletion mod.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,16 @@
export { signJWT } from "./src/sign.ts";
export { validateJWT } from "./src/validate.ts";
export { exportKeyFiles, generateKey, generateKeyPair } from "./src/cryptokeys.ts";
export type { GenerateKeyOptions, GenerateKeyPairOptions } from "./src/cryptokeys.ts";
export type {
ExportKeyFilesOptions,
GenerateKeyOptions,
GenerateKeyPairOptions,
SupportedGenerateKeyAlgorithms,
SupportedGenerateKeyPairAlgorithms,
} from "./src/cryptokeys.ts";
export type { JWTOptions } from "./src/options.ts";
export type { JWTPayload } from "./src/standardclaims.ts";

//Aliases
export { signJWT as createJWT } from "./src/sign.ts";
export { validateJWT as verifyJWT } from "./src/validate.ts";
Loading

0 comments on commit db6fab8

Please sign in to comment.