Skip to content

Commit

Permalink
Simplify request wrapper (#218)
Browse files Browse the repository at this point in the history
* Simplify request wrapper

* Remove deprecated jwksObject

* Migrate from callbacks to async/await

Co-authored-by: Adam Mcgrath <adam.mcgrath@auth0.com>
  • Loading branch information
davidpatrick and adamjmcgrath committed Feb 24, 2021
1 parent 2408cac commit b66e83f
Show file tree
Hide file tree
Showing 20 changed files with 454 additions and 1,032 deletions.
45 changes: 15 additions & 30 deletions README.md
Expand Up @@ -22,17 +22,12 @@ const client = jwksClient({
strictSsl: true, // Default value
jwksUri: 'https://sandrino.auth0.com/.well-known/jwks.json',
requestHeaders: {}, // Optional
requestAgentOptions: {}, // Optional
timeout: 30000, // Defaults to 30s
proxy: '[protocol]://[username]:[pass]@[address]:[port]', // Optional
timeout: 30000 // Defaults to 30s
});

const kid = 'RkI5MjI5OUY5ODc1N0Q4QzM0OUYzNkVGMTJDOUEzQkFCOTU3NjE2Rg';
client.getSigningKey(kid, (err, key) => {
const signingKey = key.getPublicKey();

// Now I can use this to configure my Express or Hapi middleware
});
const key = await client.getSigningKey(kid);
const signingKey = key.getPublicKey();
```

> Note that all methods on the `JwksClient` have asynchronous equivalents, where the promisified name is suffixed with `Async`, e.g., `client.getSigningKeyAsync(kid).then(key => { /* ... */ })`;
Expand All @@ -59,11 +54,8 @@ const client = jwksClient({
});

const kid = 'RkI5MjI5OUY5ODc1N0Q4QzM0OUYzNkVGMTJDOUEzQkFCOTU3NjE2Rg';
client.getSigningKey(kid, (err, key) => {
const signingKey = key.getPublicKey();

// Now I can use this to configure my Express or Hapi middleware
});
const key = await client.getSigningKey(kid);
const signingKey = key.getPublicKey();
```

### Rate Limiting
Expand All @@ -80,39 +72,32 @@ const client = jwksClient({
});

const kid = 'RkI5MjI5OUY5ODc1N0Q4QzM0OUYzNkVGMTJDOUEzQkFCOTU3NjE2Rg';
client.getSigningKey(kid, (err, key) => {
const signingKey = key.getPublicKey();

// Now I can use this to configure my Express or Hapi middleware
});
const key = await client.getSigningKey(kid);
const signingKey = key.getPublicKey();
```

### Using AgentOptions for TLS/SSL Configuration
### Using Request Agent for TLS/SSL Configuration

The `requestAgentOptions` property can be used to configure SSL/TLS options. An
The `requestAgent` property can be used to configure SSL/TLS options. An
example use case is providing a trusted private (i.e. enterprise/corporate) root
certificate authority to establish TLS communication with the `jwks_uri`.

```js
const jwksClient = require("jwks-rsa");
const https = require('https');
const client = jwksClient({
strictSsl: true, // Default value
jwksUri: 'https://my-enterprise-id-provider/.well-known/jwks.json',
requestHeaders: {}, // Optional
requestAgentOptions: {
requestAgent: new https.Agent({
ca: fs.readFileSync(caFile)
}
})
});
```

For more information, see [the NodeJS request library `agentOptions`
documentation](https://github.com/request/request#using-optionsagentoptions).

### Proxy configuration

There are two ways to configure the usage of a proxy:
- Provide the ```proxy``` option when initialiting the client as shown above
- Provide the ```HTTP_PROXY```, ```HTTPS_PROXY``` and ```NO_PROXY``` environment variables
You can configure a proxy with using a [custom http(s) agent](https://github.com/TooTallNate/node-https-proxy-agent) in the `requestAgent` option.

### Loading keys from local file, environment variable, or other externals

Expand All @@ -121,9 +106,9 @@ The `getKeysInterceptor` property can be used to fetch keys before sending a req
```js
const client = new JwksClient({
jwksUri: 'https://my-enterprise-id-provider/.well-known/jwks.json',
getKeysInterceptor: (cb) => {
getKeysInterceptor: () => {
const file = fs.readFileSync(jwksFile);
return cb(null, file.keys);
return file.keys;
}
});
```
Expand Down
40 changes: 10 additions & 30 deletions index.d.ts
@@ -1,12 +1,12 @@
import { SecretCallback, SecretCallbackLong } from 'express-jwt';
import { AgentOptions as HttpAgentOptions } from 'http';
import { AgentOptions as HttpsAgentOptions } from 'https';
import { Agent as HttpAgent } from 'http';
import { Agent as HttpsAgent } from 'https';

declare function JwksRsa(options: JwksRsa.ClientOptions): JwksRsa.JwksClient;
declare function JwksRsa(options: JwksRsa.Options): JwksRsa.JwksClient;

declare namespace JwksRsa {
class JwksClient {
constructor(options: ClientOptions | ClientOptionsWithObject);
constructor(options: Options);

getKeys(cb: (err: Error | null, keys: unknown) => void): void;
getKeysAsync(): Promise<unknown>;
Expand All @@ -20,48 +20,28 @@ declare namespace JwksRsa {
[key: string]: string;
}

interface ClientOptions {
interface Options {
jwksUri: string;
rateLimit?: boolean;
cache?: boolean;
cacheMaxEntries?: number;
cacheMaxAge?: number;
jwksRequestsPerMinute?: number;
proxy?: string;
strictSsl?: boolean;
requestHeaders?: Headers;
timeout?: number;
requestAgentOptions?: HttpAgentOptions | HttpsAgentOptions;
requestAgent?: HttpAgent | HttpsAgent;
fetcher?(jwksUri: string): Promise<{ keys: SigningKey[] }>;
getKeysInterceptor?(cb: (err: Error | null, keys: SigningKey[]) => void): void;
}

interface ClientOptionsWithObject extends Omit<ClientOptions, 'jwksUri'> {
/**
* @deprecated jwksObject should not be used. Use getKeysInterceptor as a replacement
*/
jwksObject: { keys: SigningKey[] };
}

interface CertSigningKey {
kid: string;
alg: string;
getPublicKey(): string;
publicKey: string;
}

interface Options {
jwksUri: string;
rateLimit?: boolean;
cache?: boolean;
cacheMaxEntries?: number;
cacheMaxAge?: number;
jwksRequestsPerMinute?: number;
strictSsl?: boolean;
requestHeaders?: Headers;
requestAgentOptions?: HttpAgentOptions | HttpsAgentOptions;
handleSigningKeyError?(err: Error, cb: (err: Error) => void): any;
}

interface RsaSigningKey {
kid: string;
alg: string;
Expand All @@ -75,13 +55,13 @@ declare namespace JwksRsa {

function passportJwtSecret(options: ExpressJwtOptions): SecretCallback;

interface ExpressJwtOptions extends ClientOptions {
interface ExpressJwtOptions extends Options {
handleSigningKeyError?: (err: Error | null, cb: (err: Error | null) => void) => void;
}

function hapiJwt2Key(options: HapiJwtOptions): (decodedToken: DecodedToken, cb: HapiCallback) => void;

interface HapiJwtOptions extends ClientOptions {
interface HapiJwtOptions extends Options {
handleSigningKeyError?: (err: Error | null, cb: HapiCallback) => void;
}

Expand All @@ -100,7 +80,7 @@ declare namespace JwksRsa {

function koaJwtSecret(options: KoaJwtOptions): (header: TokenHeader) => Promise<string>;

interface KoaJwtOptions extends ClientOptions {
interface KoaJwtOptions extends Options {
handleSigningKeyError?(err: Error | null): Promise<void>;
}

Expand Down

0 comments on commit b66e83f

Please sign in to comment.