Skip to content

Commit

Permalink
add test for ES256; update README; bump version
Browse files Browse the repository at this point in the history
  • Loading branch information
sagi committed Dec 12, 2020
1 parent 8ce0d6d commit 7f41094
Show file tree
Hide file tree
Showing 5 changed files with 61 additions and 8 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ Where:

- **`privateKeyPEM`** is the private key `string` in `PEM` format.
- **`payload`** is the `JSON` payload to be signed, i.e. the `{ aud, iat, exp, iss, sub, scope, ... }`.
- **`alg`** is the signing algorithm as defined in [`RFC7518`](https://tools.ietf.org/html/rfc7518#section-3.1), currently only `RS256` is supported.
- **`alg`** is the signing algorithm as defined in [`RFC7518`](https://tools.ietf.org/html/rfc7518#section-3.1), currently only `RS256` and `ES256` are supported.
- **`cryptoImpl`** is a `WebCrypto` `API` implementation. Cloudflare Workers support `WebCrypto` out of the box. For `Node.js` you can use [`node-webcrypto-ossl`](https://github.com/PeculiarVentures/node-webcrypto-ossl) - see examples below and in the tests.
- **`headerAdditions`** is an object with keys and string values to be added to the header of the `JWT`.

Expand Down Expand Up @@ -112,7 +112,7 @@ We use the `node-webcrypto-ossl` package to imitate the `Web Crypto API` in Node

~~~js
const { Crytpo }= require('node-webcrypto-ossl');
const cryptoImpl = new WebCrypto();
const cryptoImpl = new Crypto();
const { getTokenFromGCPServiceAccount } = require('@sagi.io/workers-jwt')

const serviceAccountJSON = { ... }
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@sagi.io/workers-jwt",
"version": "0.0.19",
"version": "0.0.20",
"description": "Generate JWTs on Cloudflare Workers using the WebCrypto API",
"author": "Sagi Kedmi <git@sagi.io> (https://sagi.io)",
"homepage": "https://sagi.io",
Expand Down
2 changes: 1 addition & 1 deletion src/__snapshots__/jwt.test.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ exports[`workers-jwt getToken 1`] = `"eyJraWQiOiI2ODk1ZWQ1MjdlNDI3ODYxMmM2ODNlMz

exports[`workers-jwt getToken; No crypto implementation 1`] = `"@sagi.io/workers-jwt: No crypto nor cryptoImpl were found."`;

exports[`workers-jwt getToken; Unsupported algorithm 1`] = `"@sagi.io/workers-jwt: Unsupported algorithm ES256."`;
exports[`workers-jwt getToken; Unsupported algorithm 1`] = `"@sagi.io/workers-jwt: Unsupported algorithm RSA-PSS."`;

exports[`workers-jwt getTokenFromGCPServiceAccount 1`] = `"eyJraWQiOiI2ODk1ZWQ1MjdlNDI3ODYxMmM2ODNlMzFlZTIwYzEwZWZjZTE0ODUxIiwiYWxnIjoiUlMyNTYiLCJ0eXAiOiJKV1QifQ.eyJhdWQiOiJodHRwczovL3NhZ2kuaW8iLCJpc3MiOiJjZnctcmVzdC1hcGktdGVzdDJAYXhhbXBsZS1wcm9qZWN0LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwic3ViIjoiY2Z3LXJlc3QtYXBpLXRlc3QyQGF4YW1wbGUtcHJvamVjdC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsImlhdCI6MTUzMDUxODIwNywiZXhwIjoxNTMwNTIxODA3LCJzY29wZSI6ImJsYTp4eXoifQ.QAlhoyzrTw1s087-CwohPgdZ9KSFckeCkQJU5sVN1oA0AMKoHXopk8DQdyyqGSBSrEGfKz127Kdc4BahMpSvsOuA6rpCiT7KxOv4skPm8fVGRA2Gw6hcDWpJTBmk7XZAXTxjIHR1YGbv3g9KNC6_d4aTvr3_mOJTjlDFsvIGtuHKMGDfDxHLk3ctE1V911MfouCyJdCS73-abRyvHETLcRREg11vWUWy-5ELR2kLbfsvBcQOfthV2Oqv94kJaxeE9kV5uqR-SR-gGSmzWqFQXScHXBSDZ-3-7FYPdBEHk1LcCq71iHbmTLdl5EgJCc88N381Ad5QTpVCvXt45uA8Rg"`;

Expand Down
6 changes: 3 additions & 3 deletions src/jwt.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,16 @@ import { getEncodedMessage, getDERfromPEM, str2ab } from './utils';
import '@sagi.io/globalthis';
import { Base64 } from 'js-base64';

const algorithms = {
export const algorithms = {
RS256: {
name: 'RSASSA-PKCS1-v1_5',
hash: { name: 'SHA-256' },
},
ES256: {
name: 'ECDSA',
namedCurve: 'P-256',
hash: 'SHA-256'
}
hash: { name: 'SHA-256' },
},
};

export const getHeader = (alg, headerAdditions) => ({
Expand Down
55 changes: 54 additions & 1 deletion src/jwt.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import * as jwt from './jwt';
import * as utils from './utils';
import '@sagi.io/globalthis';
import { Crypto } from 'node-webcrypto-ossl';
import { Base64 } from 'js-base64';

describe('workers-jwt', () => {
const cryptoImpl = new Crypto();
Expand Down Expand Up @@ -34,6 +35,58 @@ describe('workers-jwt', () => {
expect(token).toMatchSnapshot();
});

test('getToken; ES256', async () => {
// XXX Don't worry - this key was randomly generated with:
// $ openssl ecparam -name secp256k1 -genkey -noout
const privateKeyPEM =
`-----BEGIN EC PRIVATE KEY-----\n` +
`MHQCAQEEIKRRbvj9QDE7MGUOD/x64sk9MTS2Wj4bY6Nh0j/fr9EWoAcGBSuBBAAK\n` +
`oUQDQgAElJ1V5EYr4MDy1K33yzISzIB9ep5dVRUlld1w0liPGz0gTUNiPqgzSVSC\n` +
`/p9ocIoVIrsp7dSrxYxk3cQ8k/I8mw==\n` +
`-----END EC PRIVATE KEY-----`;

const iat = parseInt(Date.now() / 1000);
const exp = iat + 60 * 60;
const iss = 'satoshin@gmx.com';
const sub = `satoshin@gmx.com`;
const aud = 'https://sagi.io';
const scope = 'bla:xyz';
const payload = { iss, sub, iat, exp, aud, scope };
const headerAdditions = { kid: 'deadbeef' };

const token = await jwt.getToken({
privateKeyPEM,
payload,
alg: 'ES256',
headerAdditions,
cryptoImpl,
});

const b64SignedInput = token.split('.').slice(0, 2).join('.');
const b64Signature = token.split('.')[2];

const b64SignedInputArrBuf = utils.str2ab(b64SignedInput);
const signature = Base64.toUint8Array(b64Signature);
const algorithm = jwt.algorithms['ES256'];

const privateKeyDER = utils.getDERfromPEM(privateKeyPEM);
const publicKey = await crypto.subtle.importKey(
'pkcs8',
privateKeyDER,
algorithm,
false,
['verify']
);

const verified = await crypto.subtle.verify(
algorithm,
publicKey,
signature,
b64SignedInputArrBuf
);
expect(verified).toBe(true);
});

test('getToken; Unsupported algorithm', async () => {
// XXX Don't worry - this service account was deleted (i.e. can't be abused).
const sa = require('./testdata/service_account.json');
Expand All @@ -53,7 +106,7 @@ describe('workers-jwt', () => {
payload,
headerAdditions,
cryptoImpl,
alg: 'ES256',
alg: 'RSA-PSS',
})
).rejects.toThrowErrorMatchingSnapshot();
});
Expand Down

0 comments on commit 7f41094

Please sign in to comment.