Skip to content
Merged
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
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
MIT License

Copyright (c) 2024 cross-org <https://github.com/cross-org>
Copyright (c) 2024-2026 cross-org <https://github.com/cross-org>

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
Expand Down
12 changes: 5 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -120,12 +120,10 @@ const { privateKey, publicKey } = await generateKeyPair("RS512");
const key = await generateKeyPair({ algorithm: "RS512" });
```

- **`exportPEMKey(key: CryptoKey, filePathOrOptions?: string | ExportPEMKeyOptions): Promise<string>`** (Experimental)
- **`importPEMKey(keyDataOrPath: string, algorithm: SupportedKeyPairAlgorithms): Promise<CryptoKey>`** (Experimental)
- **`exportPEMKey(key: CryptoKey, filePathOrOptions?: string | ExportPEMKeyOptions): Promise<string>`**
- **`importPEMKey(keyDataOrPath: string, algorithm: SupportedKeyPairAlgorithms): Promise<CryptoKey>`**

```javascript
// Experimental.

// Generate and export RS512 keys in PEM-format. (filePath and write mode can be supplied as optional second parameter at export)
const { privateKey, publicKey } = await generateKeyPair("RS512");
await exportPEMKey(privateKey, "./private_key_RS512.pem");
Expand Down Expand Up @@ -431,13 +429,13 @@ const insecureString = "shortString";
const key = await generateKey(insecureString, keyOptions);
```

Export/import a key pair to and from local files. (Experimental)
Export/import a key pair to and from local files.

```javascript
// Generate and export RS512 keys in PEM-format.
const { privateKey, publicKey } = await generateKeyPair("RS512");
await exportPEMKey(privateKey, "./private_key_RS512a.pem");
await exportPEMKey(publicKey, "./public_key_RS512a.pem");
await exportPEMKey(privateKey, "./private_key_RS512.pem");
await exportPEMKey(publicKey, "./public_key_RS512.pem");

// Import RS512 keys from PEM-format.
const importedPrivateKey = await importPEMKey("./private_key_RS512.pem", "RS512");
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.6.0",
"version": "1.0.0",
"exports": "./mod.ts",

"tasks": {
Expand Down
23 changes: 10 additions & 13 deletions src/core/validate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,12 @@ export async function validateJWT(
}
}

const payload = JSON.parse(textDecode(decodeBase64Url(jwtParts[1])));
let payload: JWTPayload;
try {
payload = JSON.parse(textDecode(decodeBase64Url(jwtParts[1])));
} catch (_error) {
throw new JWTParseError("Invalid JWT payload: malformed JSON");
}

validateClaims(payload, options);

Expand Down Expand Up @@ -251,12 +256,8 @@ export function unsafeParseJWT(jwt: string): JWTPayload {
const jwtParts = validateParts(jwt);
const payload = JSON.parse(textDecode(decodeBase64Url(jwtParts[1])));
return payload;
} catch (error) {
if (error instanceof Error) {
throw new JWTParseError(error.message);
} else {
throw new JWTParseError("An unknown error occurred while parsing the JWT.");
}
} catch (_error) {
throw new JWTParseError("Invalid JWT format or malformed payload");
}
}

Expand All @@ -272,11 +273,7 @@ export function unsafeParseJOSEHeader(jwt: string): JOSEHeader {
const jwtParts = validateParts(jwt);
const payload = JSON.parse(textDecode(decodeBase64Url(jwtParts[0])));
return payload;
} catch (error) {
if (error instanceof Error) {
throw new JWTParseError(error.message);
} else {
throw new JWTParseError("An unknown error occurred while parsing the JOSE header.");
}
} catch (_error) {
throw new JWTParseError("Invalid JWT format or malformed header");
}
}
14 changes: 10 additions & 4 deletions src/crypto/sign-verify/rsapss.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,12 @@ import type { JWTOptions } from "../../types/options.ts";
* @returns {Promise<string>} A promise resolving to the base64url-encoded RSA-PSS signature.
*/
export async function signWithRSAPSS(key: CryptoKey, data: string, options?: JWTOptions) {
(key.algorithm as RsaPssParams).saltLength = options?.saltLength || 32;
const algorithm = {
name: key.algorithm.name,
saltLength: options?.saltLength || 32,
};
const signature = await crypto.subtle.sign(
key.algorithm,
algorithm,
key,
textEncode(data) as BufferSource,
);
Expand All @@ -32,9 +35,12 @@ export async function signWithRSAPSS(key: CryptoKey, data: string, options?: JWT
* @returns {Promise<boolean>} A promise resolving to `true` if the signature is valid, `false` otherwise.
*/
export async function verifyWithRSAPSS(key: CryptoKey, data: string, signature: string, options?: JWTOptions) {
(key.algorithm as RsaPssParams).saltLength = options?.saltLength || 32;
const algorithm = {
name: key.algorithm.name,
saltLength: options?.saltLength || 32,
};
const isValid = await crypto.subtle.verify(
key.algorithm,
algorithm,
key,
decodeBase64Url(signature),
textEncode(data) as BufferSource,
Expand Down
Loading