Skip to content

Commit

Permalink
getToken takes only a single set of options
Browse files Browse the repository at this point in the history
  • Loading branch information
aarongranick-okta committed Jan 29, 2020
1 parent 8a29ce5 commit 1d8082c
Show file tree
Hide file tree
Showing 6 changed files with 165 additions and 54 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@

- [#317](https://github.com/okta/okta-auth-js/pull/317) - `pkce` option is now `true` by default. `grantType` option is removed.

- [#320](https://github.com/okta/okta-auth-js/pull/320) - `getWithRedirect`, `getWithPopup`, and `getWithoutPrompt` previously took 2 sets of option objects as parameters, a set of "oauthOptions" and additional options. These methods now take a single options object which can hold all available options. Passing a second options object will cause an exception to be thrown.

- [#321](https://github.com/okta/okta-auth-js/pull/321)
- Default responseType when using implicit flow is now ['token', 'id_token'].
- When both access token and id token are returned, the id token's at_hash claim will be validated against the access token
Expand Down
33 changes: 19 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,10 @@
* [Node JS Usage](#node-js-usage)
* [Contributing](#contributing)

The Okta Auth JavaScript SDK builds on top of our [Authentication API](https://developer.okta.com/docs/api/resources/authn) and [OAuth 2.0 API](https://developer.okta.com/docs/api/resources/oidc) to enable you to create a fully branded sign-in experience using JavaScript.
The Okta Auth JavaScript SDK builds on top of our [Authentication API](https://developer.okta.com/docs/api/resources/authn) and [OpenID Connect & OAuth 2.0 API](https://developer.okta.com/docs/api/resources/oidc) to enable you to create a fully branded sign-in experience using JavaScript.

You can learn more on the [Okta + JavaScript][lang-landing] page in our documentation.

## Release status

This library uses semantic versioning and follows Okta's [library version policy](https://developer.okta.com/code/library-versions/).

:heavy_check_mark: The current stable major version series is: `2.x`
Expand Down Expand Up @@ -155,7 +153,7 @@ var config = {
var authClient = new OktaAuth(config);
```

### [OpenID Connect](https://developer.okta.com/docs/api/resources/oidc) options
### Configuration options

These configuration options can be included when instantiating Okta Auth JS (`new OktaAuth(config)`) or in `token.getWithoutPrompt`, `token.getWithPopup`, or `token.getWithRedirect` (unless noted otherwise). If included in both, the value passed in the method takes priority.

Expand Down Expand Up @@ -377,8 +375,8 @@ var config = {
* [session.get](#sessionget)
* [session.refresh](#sessionrefresh)
* [token](#token)
* [token.getWithoutPrompt](#tokengetwithoutpromptoauthoptions)
* [token.getWithPopup](#tokengetwithpopupoauthoptions)
* [token.getWithoutPrompt](#tokengetwithoutpromptoptions)
* [token.getWithPopup](#tokengetwithpopupoptions)
* [token.getWithRedirect](#tokengetwithredirectoptions)
* [token.parseFromUrl](#tokenparsefromurloptions)
* [token.decode](#tokendecodeidtokenstring)
Expand Down Expand Up @@ -1518,7 +1516,7 @@ authClient.session.refresh()

### `token`

#### Extended OpenID Connect options
#### Authorize options

The following configuration options can **only** be included in `token.getWithoutPrompt`, `token.getWithPopup`, or `token.getWithRedirect`.

Expand All @@ -1530,8 +1528,14 @@ The following configuration options can **only** be included in `token.getWithou
| `scopes` | Specify what information to make available in the returned `id_token` or `access_token`. For OIDC, you must include `openid` as one of the scopes. Defaults to `['openid', 'email']`. For a list of available scopes, see [Scopes and Claims](https://developer.okta.com/docs/api/resources/oidc#access-token-scopes-and-claims). |
| `state` | A string that will be passed to `/authorize` endpoint and returned in the OAuth response. The value is used to validate the OAuth response and prevent cross-site request forgery (CSRF). The `state` value passed to [getWithRedirect](#tokengetwithredirectoptions) will be returned along with any requested tokens from [parseFromUrl](#tokenparsefromurloptions). Your app can use this string to perform additional validation and/or pass information from the login page. Defaults to a random string. |
| `nonce` | Specify a nonce that will be validated in an `id_token`. This is usually only provided during redirect flows to obtain an authorization code that will be exchanged for an `id_token`. Defaults to a random string. |
| `idp` | Identity provider to use if there is no Okta Session. |
| `idpScope` | A space delimited list of scopes to be provided to the Social Identity Provider when performing [Social Login](social-login) These scopes are used in addition to the scopes already configured on the Identity Provider. |
| `display` | The display parameter to be passed to the Social Identity Provider when performing [Social Login](social-login). |
| `prompt` | Determines whether the Okta login will be displayed on failure. Use `none` to prevent this behavior. Valid values: `none`, `consent`, `login`, or `consent login`. See [Parameter details](https://developer.okta.com/docs/reference/api/oidc/#parameter-details) for more information. |
| `maxAge` | Allowable elapsed time, in seconds, since the last time the end user was actively authenticated by Okta. |
| `loginHint` | A username to prepopulate if prompting for authentication. |

For a list of all available parameters that can be passed to the `/authorize` endpoint, see Okta's [Authorize Request API](https://developer.okta.com/docs/api/resources/oidc#request-parameters).
For more details, see Okta's [Authorize Request API](https://developer.okta.com/docs/api/resources/oidc#request-parameters).

##### Example

Expand Down Expand Up @@ -1559,11 +1563,11 @@ authClient.token.getWithoutPrompt({
});
```

#### `token.getWithoutPrompt(oauthOptions)`
#### `token.getWithoutPrompt(options)`

When you've obtained a sessionToken from the authorization flows, or a session already exists, you can obtain a token or tokens without prompting the user to log in.

* `oauthOptions` - See [Extended OpenID Connect options](#extended-openid-connect-options)
* `options` - See [Authorize options](#authorize-options)

```javascript
authClient.token.getWithoutPrompt({
Expand All @@ -1581,14 +1585,14 @@ authClient.token.getWithoutPrompt({
});
```

#### `token.getWithPopup(oauthOptions)`
#### `token.getWithPopup(options)`

Create token with a popup.

* `oauthOptions` - See [Extended OpenID Connect options](#extended-openid-connect-options)
* `options` - See [Authorize options](#authorize-options)

```javascript
authClient.token.getWithPopup(oauthOptions)
authClient.token.getWithPopup(options)
.then(function(res) {
var tokens = res.tokens;

Expand All @@ -1604,7 +1608,7 @@ authClient.token.getWithPopup(oauthOptions)

Create token using a redirect. After a successful authentication, the browser will be redirected to the configured [redirectUri](#additional-options). The authorization code, access, or ID Tokens will be available as parameters appended to this URL. By default, values will be in the hash fragment of the URL (for SPA applications) or in the search query (for Web applications). SPA Applications using the PKCE flow can opt to receive the authorization code in the search query by setting the [responseMode](#additional-options) option to "query".

* `oauthOptions` - See [Extended OpenID Connect options](#extended-openid-connect-options)
* `options` - See [Authorize options](#authorize-options)

```javascript
authClient.token.getWithRedirect({
Expand Down Expand Up @@ -1964,3 +1968,4 @@ We're happy to accept contributions and PRs! Please see the [contribution guide]
[lang-landing]: https://developer.okta.com/code/javascript
[github-issues]: https://github.com/okta/okta-auth-js/issues
[github-releases]: https://github.com/okta/okta-auth-js/releases
[social-login]: https://developer.okta.com/docs/concepts/social-login/
5 changes: 4 additions & 1 deletion packages/okta-auth-js/lib/oauthUtil.js
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,10 @@ function validateClaims(sdk, claims, validationParams) {
}
}

function getOAuthUrls(sdk, oauthParams, options) {
function getOAuthUrls(sdk, options) {
if (arguments.length > 2) {
throw new AuthSdkError('As of version 3.0, "getOAuthUrls" takes only a single set of options');
}
options = options || {};

// Get user-supplied arguments
Expand Down
62 changes: 36 additions & 26 deletions packages/okta-auth-js/lib/token.js
Original file line number Diff line number Diff line change
Expand Up @@ -426,11 +426,13 @@ function buildAuthorizeParams(oauthParams) {
* @param {String} [options.popupTitle] Title dispayed in the popup.
* Defaults to 'External Identity Provider User Authentication'
*/
function getToken(sdk, oauthOptions, options) {
oauthOptions = oauthOptions || {};
function getToken(sdk, options) {
if (arguments.length > 2) {
return Promise.reject(new AuthSdkError('As of version 3.0, "getToken" takes only a single set of options'));
}
options = options || {};

return prepareOauthParams(sdk, oauthOptions)
return prepareOauthParams(sdk, options)
.then(function(oauthParams) {

// Start overriding any options that don't make sense
Expand All @@ -444,9 +446,9 @@ function getToken(sdk, oauthOptions, options) {
display: 'popup'
};

if (oauthOptions.sessionToken) {
if (options.sessionToken) {
util.extend(oauthParams, sessionTokenOverrides);
} else if (oauthOptions.idp) {
} else if (options.idp) {
util.extend(oauthParams, idpOverrides);
}

Expand All @@ -456,8 +458,8 @@ function getToken(sdk, oauthOptions, options) {
urls;

// Get authorizeUrl and issuer
urls = oauthUtil.getOAuthUrls(sdk, oauthParams, options);
endpoint = oauthOptions.codeVerifier ? urls.tokenUrl : urls.authorizeUrl;
urls = oauthUtil.getOAuthUrls(sdk, oauthParams);
endpoint = options.codeVerifier ? urls.tokenUrl : urls.authorizeUrl;
requestUrl = endpoint + buildAuthorizeParams(oauthParams);

// Determine the flow type
Expand Down Expand Up @@ -557,32 +559,38 @@ function getToken(sdk, oauthOptions, options) {
});
}

function getWithoutPrompt(sdk, oauthOptions, options) {
var oauthParams = util.clone(oauthOptions) || {};
util.extend(oauthParams, {
function getWithoutPrompt(sdk, options) {
if (arguments.length > 2) {
return Promise.reject(new AuthSdkError('As of version 3.0, "getWithoutPrompt" takes only a single set of options'));
}
options = util.clone(options) || {};
util.extend(options, {
prompt: 'none',
responseMode: 'okta_post_message',
display: null
});
return getToken(sdk, oauthParams, options);
return getToken(sdk, options);
}

function getWithPopup(sdk, oauthOptions, options) {
var oauthParams = util.clone(oauthOptions) || {};
util.extend(oauthParams, {
function getWithPopup(sdk, options) {
if (arguments.length > 2) {
return Promise.reject(new AuthSdkError('As of version 3.0, "getWithPopup" takes only a single set of options'));
}
options = util.clone(options) || {};
util.extend(options, {
display: 'popup',
responseMode: 'okta_post_message'
});
return getToken(sdk, oauthParams, options);
return getToken(sdk, options);
}

function prepareOauthParams(sdk, oauthOptions) {
function prepareOauthParams(sdk, options) {
// clone and prepare options
oauthOptions = util.clone(oauthOptions) || {};
options = util.clone(options) || {};

// build params using defaults + options
var oauthParams = getDefaultOAuthParams(sdk);
util.extend(oauthParams, oauthOptions);
util.extend(oauthParams, options);

if (oauthParams.pkce === false) {
return Promise.resolve(oauthParams);
Expand Down Expand Up @@ -632,15 +640,18 @@ function prepareOauthParams(sdk, oauthOptions) {
});
}

function getWithRedirect(sdk, oauthOptions, options) {
oauthOptions = util.clone(oauthOptions) || {};
function getWithRedirect(sdk, options) {
if (arguments.length > 2) {
return Promise.reject(new AuthSdkError('As of version 3.0, "getWithRedirect" takes only a single set of options'));
}
options = util.clone(options) || {};

return prepareOauthParams(sdk, oauthOptions)
return prepareOauthParams(sdk, options)
.then(function(oauthParams) {

// Dynamically set the responseMode unless the user has provided one
// Dynamically set the responseMode unless the user has explicitly provided one
// Server-side flow requires query. Client-side apps usually prefer fragment.
if (!oauthOptions.responseMode) {
if (!options.responseMode) {
if (oauthParams.responseType.includes('code') && !oauthParams.pkce) {
// server-side flows using authorization_code
oauthParams.responseMode = 'query';
Expand All @@ -650,7 +661,7 @@ function getWithRedirect(sdk, oauthOptions, options) {
}
}

var urls = oauthUtil.getOAuthUrls(sdk, oauthParams, options);
var urls = oauthUtil.getOAuthUrls(sdk, options);
var requestUrl = urls.authorizeUrl + buildAuthorizeParams(oauthParams);

// Set session cookie to store the oauthParams
Expand Down Expand Up @@ -700,8 +711,7 @@ function renewToken(sdk, token) {

return sdk.token.getWithoutPrompt({
responseType: responseType,
scopes: token.scopes
}, {
scopes: token.scopes,
authorizeUrl: token.authorizeUrl,
userinfoUrl: token.userinfoUrl,
issuer: token.issuer
Expand Down
18 changes: 13 additions & 5 deletions packages/okta-auth-js/test/spec/oauthUtil.js
Original file line number Diff line number Diff line change
Expand Up @@ -416,13 +416,9 @@ describe('getOAuthUrls', function() {
issuer: 'https://auth-js-test.okta.com'
});

var oauthParams = options.oauthParams || {
responseType: 'id_token'
};

var result, error;
try {
result = oauthUtil.getOAuthUrls(sdk, oauthParams, options.options);
result = oauthUtil.getOAuthUrls(sdk, options.options);
} catch(e) {
error = e;
}
Expand All @@ -442,6 +438,18 @@ describe('getOAuthUrls', function() {
}
}

it('throws if an extra options object is passed', () => {
const sdk = new OktaAuth({
pkce: false,
issuer: 'https://auth-js-test.okta.com'
});

const f = function () {
oauthUtil.getOAuthUrls(sdk, {}, {});
};
expect(f).toThrowError('As of version 3.0, "getOAuthUrls" takes only a single set of options');
});

it('defaults all urls using global defaults', function() {
setupOAuthUrls({
expectedResult: {
Expand Down
Loading

0 comments on commit 1d8082c

Please sign in to comment.