old-keypairs.js/README.md

210 lines
5.5 KiB
Markdown

# Keypairs.js
Lightweight JavaScript RSA and ECDSA utils that work on Windows, Mac, and Linux
using modern node.js APIs (no need for C compiler).
A thin wrapper around [Eckles.js (ECDSA)](https://git.coolaj86.com/coolaj86/eckles.js/)
and [Rasha.js (RSA)](https://git.coolaj86.com/coolaj86/rasha.js/).
# Features
* [x] Generate keypairs
* [x] RSA
* [x] ECDSA (P-256, P-384)
* [x] PEM-to-JWK (and SSH-to-JWK)
* [x] JWK-to-PEM (and JWK-to-SSH)
* [x] Create JWTs (and sign JWS)
* [x] SHA256 JWK Thumbprints
* [ ] JWK fetching. See [Keyfetch.js](https://npmjs.com/packages/keyfetch/)
* [ ] OIDC
* [ ] Auth0
* [ ] CLI
* See [keypairs-cli](https://npmjs.com/packages/keypairs-cli/)
<!--
* [ ] generate CSR (DER as PEM or base64url)
-->
# Usage
A brief (albeit somewhat nonsensical) introduction to the APIs:
```
Keypairs.generate().then(function (pair) {
return Keypairs.export({ jwk: pair.private }).then(function (pem) {
return Keypairs.import({ pem: pem }).then(function (jwk) {
return Keypairs.thumbprint({ jwk: jwk }).then(function (thumb) {
console.log(thumb);
return Keypairs.signJwt({
jwk: keypair.private
, claims: {
iss: 'https://example.com'
, sub: 'jon.doe@gmail.com'
, exp: Math.round(Date.now()/1000) + (3 * 24 * 60 * 60)
}
});
});
});
});
});
```
By default ECDSA keys will be used since they've had native support in node
_much_ longer than RSA has, and they're smaller, and faster to generate.
## API Overview
* generate
* parse
* parseOrGenerate
* import (PEM-to-JWK)
* export (JWK-to-PEM, private or public)
* publish (Private JWK to Public JWK)
* thumbprint (JWK SHA256)
* signJwt
* signJws
#### Keypairs.generate(options)
Generates a public/private pair of JWKs as `{ private, public }`
Option examples:
* RSA `{ kty: 'RSA', modulusLength: 2048 }`
* ECDSA `{ kty: 'ECDSA', namedCurve: 'P-256' }`
When no options are supplied EC P-256 (also known as `prime256v1` and `secp256r1`) is used by default.
#### Keypairs.parse(options)
Parses either a JWK (encoded as JSON) or an x509 (encdode as PEM) and gives
back the JWK representation.
Option Examples:
* JWK { key: '{ "kty":"EC", ... }' }
* PEM { key: '-----BEGIN PRIVATE KEY-----\n...' }
* Public Key Only { key: '-----BEGIN PRIVATE KEY-----\n...', public: true }
* Must Have Private Key { key: '-----BEGIN PUBLIC KEY-----\n...', private: true }
Example:
```js
Keypairs.parse({ key: '...' }).catch(function (e) {
// could not be parsed or was a public key
console.warn(e);
return Keypairs.generate();
});
```
#### Keypairs.parseOrGenerate({ key, throw, [generate opts]... })
Parses the key. Logs a warning on failure, marches on.
(a shortcut for the above, with `private: true`)
Option Examples:
* parse key if exist, otherwise generate `{ key: process.env["PRIVATE_KEY"] }`
* generated key curve `{ key: null, namedCurve: 'P-256' }`
* generated key modulus `{ key: null, modulusLength: 2048 }`
Example:
```js
Keypairs.parseOrGenerate({ key: process.env["PRIVATE_KEY"] }).then(function (pair) {
console.log(pair.public);
})
```
Great for when you have a set of shared keys for development and randomly
generated keys in
#### Keypairs.import({ pem: '...' }
Takes a PEM in pretty much any format (PKCS1, SEC1, PKCS8, SPKI) and returns a JWK.
#### Keypairs.export(options)
Exports a JWK as a PEM.
Exports PEM in PKCS8 (private) or SPKI (public) by default.
Options
```js
{ jwk: jwk
, public: true
, encoding: 'pem' // or 'der'
, format: 'pkcs8' // or 'ssh', 'pkcs1', 'sec1', 'spki'
}
```
#### Keypairs.publish({ jwk: jwk })
**Synchronously** strips a key of its private parts and returns the public version.
#### Keypairs.thumbprint({ jwk: jwk })
Promises a JWK-spec thumbprint: URL Base64-encoded sha256
#### Keypairs.signJwt({ jwk, header, claims })
Returns a JWT (otherwise known as a protected JWS in "compressed" format).
```js
{ jwk: jwk
, claims: {
}
}
```
Header defaults:
```js
{ kid: thumbprint
, alg: 'xS256'
, typ: 'JWT'
}
```
Payload notes:
* `iat: now` is added by default (set `false` to disable)
* `exp` must be set (set `false` to disable)
* `iss` should be the base URL for JWK lookup (i.e. via OIDC, Auth0)
Notes:
`header` is actually the JWS `protected` value, as all JWTs use protected headers (yay!)
and `claims` are really the JWS `payload`.
#### Keypairs.signJws({ jwk, header, protected, payload })
This is provided for APIs like ACME (Let's Encrypt) that use uncompressed JWS (instead of JWT, which is compressed).
Options:
* `header` not what you think. Leave undefined unless you need this for the spec you're following.
* `protected` is the typical JWT-style header
* `kid` and `alg` will be added by default (these are almost always required), set `false` explicitly to disable
* `payload` can be JSON, a string, or even a buffer (which gets URL Base64 encoded)
* you must set this to something, even if it's an empty string, object, or Buffer
# Additional Documentation
Keypairs.js provides a 1-to-1 mapping to the Rasha.js and Eckles.js APIs for the following:
* generate(options)
* import({ pem: '---BEGIN...' })
* export({ jwk: { kty: 'EC', ... })
* thumbprint({ jwk: jwk })
If you want to know the algorithm-specific options that are available for those
you'll want to take a look at the corresponding documentation:
* See ECDSA documentation at [Eckles.js](https://git.coolaj86.com/coolaj86/eckles.js/)
* See RSA documentation at [Rasha.js](https://git.coolaj86.com/coolaj86/rasha.js/)