From 3138a41ed91519361a18384067994e8f1a24d1d0 Mon Sep 17 00:00:00 2001 From: Alex Layton Date: Thu, 14 Apr 2022 21:26:16 -0400 Subject: [PATCH] Fix Options type and update README --- README.md | 144 +++++++++++++++++++++++++++++++++++++-------------- package.json | 2 +- src/core.ts | 8 ++- 3 files changed, 111 insertions(+), 43 deletions(-) diff --git a/README.md b/README.md index ac960f7..d5269d0 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,5 @@ # @oada/id-client -[![Build Status](https://travis-ci.org/OADA/oada-id-client-js.svg?branch=master)](https://travis-ci.org/OADA/oada-id-client-js) [![Coverage Status](https://coveralls.io/repos/OADA/oada-id-client-js/badge.svg?branch=master)](https://coveralls.io/r/OADA/oada-id-client-js?branch=master) [![npm](https://img.shields.io/npm/v/@oada/id-client)](https://www.npmjs.com/package/@oada/id-client) [![Downloads/week](https://img.shields.io/npm/dw/@oada/id-client.svg)](https://npmjs.org/package/@oada/id-client) @@ -35,11 +34,96 @@ This will create the file `bundle.js`. - [On Server Example][] - [In Browser Example][] +## High-Level Node.JS wrapper Usage + +This version of the library wraps the core functionality +for easy use in typical Node.JS uses. + +It will pop up a window using the default browser +to take the user through the needed flows +and the return the resulting token(s). + +### getIDToken(domain, options) + +Asynchronous function for generating an ID token request against +an OADA identity provider. + +#### Parameters + +`domain` string of domain with which to log in the user. + +`options` object containing at least the following properties: + +- `metadata` object containing [client metadata][], + or string of a [`software_statement`][] JWT +- `privateKey` a private JWK for use in the JWT bearer client auth + (required for code flow) +- `params` [Optional OpenID Connect parameters][oidparams] placed in `params` as + string properties will be used (e.g. `display`, `prompt`, `login_hint`) + +[Optional OpenID Connect parameters][oidparams] placed in options as +string properties will be used (e.g. `display`, `prompt`, `login_hint`). + +#### Usage Example + +```typescript +const options = { + metadata: { + /* See spec linked above */ + }, +}; + +const domain = /* Set domain based on text box, dropdown, etc. */; + +// Promise will resolve after user completes the flow in the browser +const idToken = await oadaIdClient.getIDToken(domain, options); +console.dir(idToken); +``` + +### getAccessToken(domain, options) + +Asynchronous function for generating an access token request against an +OADA compliant API. + +#### Parameters + +`domain` string of domain from which to get an OADA API access token. +The value passed to the function can be overridden by a query or form +parameter with a name of `domain`. + +`options` object containing at least the following properties: + +- `metadata` object containing [client metadata][], + or string of a [`software_statement`][] JWT +- [`scope`][] space separated string of OAuth scopes for the request access + token to have. +- `privateKey` a private JWK for use in the JWT bearer client auth + (required for code flow) +- `params` [Optional OpenID Connect parameters][oidparams] placed in `params` as + string properties will be used (e.g. `display`, `prompt`, `login_hint`) + +#### Usage Example + +```typescript +const options = { + metadata: { + /* See spec linked above */ + }, + scope: 'some.oada.defined.scope', +}; + +const domain = /* Set domain based on text box, dropdown, etc. */; + +// Promise will resolve after user completes the flow in the browser +const accessToken = await oadaIdClient.getAccessToken(domain, options); +console.dir(accessToken); +``` + ## Connect Style "Middleware" Wrapper Usage -Version of the library functions which wrap the core functionality +This version of the library wraps the core functionality for use as connect style "middleware". -This can be used in a NodeJS server using a compatible web development +This can be used in a Node.JS server using a compatible web development framework, such as express. For a working example of using this wrapper, see the [on server example][]. @@ -57,13 +141,10 @@ parameter with a name of `domain`. `options` object containing at least the following properties: -- [`metadata`][] object containing client metadata, +- `metadata` object containing [client metadata][], or string of a [`software_statement`][] JWT -- `privateKey` - - `pem` string or buffer containing your client's PEM encoded private RSA - key - - [`kid`][] string containing the key ID parameter, - for finding the corresponding public key where your client is registered +- `privateKey` a private JWK for use in the JWT bearer client auth + (required for code flow) - `params` [Optional OpenID Connect parameters][oidparams] placed in `params` as string properties will be used (e.g. `display`, `prompt`, `login_hint`) @@ -99,13 +180,10 @@ parameter with a name of `domain`. `options` object containing at least the following properties: -- [`metadata`][] object containing client metadata, +- `metadata` object containing [client metadata][], or string of a [`software_statement`][] JWT -- `privateKey` - - `pem` string or buffer containing your client's PEM encoded private RSA - key - - [`kid`][] string containing the key ID parameter, - for finding the corresponding public key where your client is registered +- `privateKey` a private JWK for use in the JWT bearer client auth + (required for code flow) - [`scope`][] space separated string of OAuth scopes for the request access token to have. - `params` [Optional OpenID Connect parameters][oidparams] placed in `params` as @@ -135,7 +213,7 @@ app.use( Middleware for handling redirects from `getIDToken` or `getAccessToken` middlewares. -In most case you will apply this middleware in two locations, +In most cases, you will apply this middleware in two locations, one to receive `getIDToken` redirects and another to receive `getAccessToken` redirects. @@ -171,12 +249,12 @@ app.use( ## Browser Wrapper Usage -Version of the library functions which wrap the core functionality +This version of the library wraps the core functionality for easy use in the browser. For a working example of using this wrapper, see the [in browser example][]. -### getIDToken(domain, options, callback) +### getIDToken(domain, options) Asynchronous function for generating an ID token request against an OADA identity provider. @@ -187,7 +265,7 @@ an OADA identity provider. `options` object containing at least the following properties: -- [`metadata`][] object containing client metadata, +- `metadata` object containing [client metadata][], or string of a [`software_statement`][] JWT - `params` [Optional OpenID Connect parameters][oidparams] placed in `params` as string properties will be used (e.g. `display`, `prompt`, `login_hint`) @@ -195,8 +273,6 @@ an OADA identity provider. [Optional OpenID Connect parameters][oidparams] placed in options as string properties will be used (e.g. `display`, `prompt`, `login_hint`). -`callback` function of the form `function(err, idToken)`. - #### Usage Example ```typescript @@ -208,16 +284,11 @@ const options = { const domain = /* Set domain based on text box, dropdown, etc. */; -oadaIdClient.getIDToken(domain, options, function (err, idToken) { - if (err) { - return console.dir(err); - } // Soemthing went wrong - - console.dir(idToken); -}); +const idToken = await oadaIdClient.getIDToken(domain, options); +console.dir(idToken); ``` -### getAccessToken(domain, options, callback) +### getAccessToken(domain, options) Asynchronous function for generating an access token request against an OADA compliant API. @@ -230,15 +301,13 @@ parameter with a name of `domain`. `options` object containing at least the following properties: -- [`metadata`][] object containing client metadata, +- `metadata` object containing [client metadata][], or string of a [`software_statement`][] JWT - [`scope`][] space separated string of OAuth scopes for the request access token to have. - `params` [Optional OpenID Connect parameters][oidparams] placed in `params` as string properties will be used (e.g. `display`, `prompt`, `login_hint`) -`callback` function of the form `function(err, accessToken)`. - #### Usage Example ```typescript @@ -251,13 +320,8 @@ const options = { const domain = /* Set domain based on text box, dropdown, etc. */; -oadaIdClient.getAccessToken(domain, options, function (err, accessToken) { - if (err) { - return console.dir(err); - } // Something went wrong - - console.dir(accessToken); -}); +const accessToken = await oadaIdClient.getAccessToken(domain, options); +console.dir(accessToken); ``` ### handleRedirect() @@ -300,5 +364,5 @@ Not yet documented. [`redirect_uri`]: http://tools.ietf.org/html/rfc6749#section-3.1.2 'RFC6794 Section 3.1.2' [`scope`]: http://tools.ietf.org/html/rfc6749#section-3.3 'RFC6794 Section 3.3' [`kid`]: https://tools.ietf.org/html/draft-ietf-jose-json-web-key-31#section-4.5 'JWK Section 4.5' -[`metadata`]: https://tools.ietf.org/html/draft-ietf-oauth-dyn-reg#section-2 'oauth-dyn-reg Section 2' +[client metadata]: https://tools.ietf.org/html/draft-ietf-oauth-dyn-reg#section-2 'oauth-dyn-reg Section 2' [`software_statement`]: https://tools.ietf.org/html/draft-ietf-oauth-dyn-reg#section-2.3 'oauth-dyn-reg Section 2.3' diff --git a/package.json b/package.json index 225b800..573b086 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@oada/id-client", - "version": "2.0.1", + "version": "2.0.2", "description": "OADA identity client library for Node.JS and Browser", "main": "index.js", "types": "index.d.ts", diff --git a/src/core.ts b/src/core.ts index fb8b0f8..2cce063 100644 --- a/src/core.ts +++ b/src/core.ts @@ -54,7 +54,7 @@ export interface Options { metadata: Metadata | string; scope?: string | readonly string[]; params?: QueryParameters; - privateKey: jwku.JWK; + privateKey?: jwku.JWK; redirect?: string; display?: string; } @@ -68,7 +68,7 @@ export interface Configuration extends OADAConfiguration { } export interface State { - key: jwku.JWK; + key?: jwku.JWK; domain: string; conf: Configuration; options: RegistrationData; @@ -267,6 +267,10 @@ async function exchangeCode(codeState: State, query: QueryParameters) { return verifyIDToken(codeState, query); } + if (!codeState.key) { + throw new Error('No key provided, cannot perform code exchange'); + } + const assertion = await generate({ key: codeState.key, issuer: codeState.options.client_id,