From c7f698eadae6b5753fc85ebde79b624cf3028d60 Mon Sep 17 00:00:00 2001 From: "denys.oblohin" Date: Mon, 24 Oct 2022 11:45:36 +0300 Subject: [PATCH] moved enrollAuthenticator to top level --- README.md | 93 ++++++++++++++------------- lib/oidc/enrollAuthenticator.ts | 2 +- lib/oidc/factory/api.ts | 10 --- lib/oidc/mixin/index.ts | 18 ++++++ lib/oidc/types/api.ts | 2 +- lib/oidc/util/prepareTokenParams.ts | 3 +- test/apps/app/src/testApp.ts | 2 +- test/spec/oidc/enrollAuthenticator.ts | 10 ++- test/types/token.test-d.ts | 8 +-- 9 files changed, 77 insertions(+), 71 deletions(-) diff --git a/README.md b/README.md index f0c48d739..7c798688e 100644 --- a/README.md +++ b/README.md @@ -880,6 +880,7 @@ This is accomplished by selecting a single tab to handle the network requests to * [forgotPassword](#forgotpasswordoptions) * [unlockAccount](#unlockaccountoptions) * [verifyRecoveryToken](#verifyrecoverytokenoptions) +* [enrollAuthenticator](#enrollauthenticatoroptions) * [webfinger](#webfingeroptions) * [fingerprint](#fingerprintoptions) * [isAuthenticated](#isauthenticatedoptions) @@ -915,7 +916,6 @@ This is accomplished by selecting a single tab to handle the network requests to * [token.isLoginRedirect](#tokenisloginredirect) * [token.prepareTokenParams](#tokenpreparetokenparams) * [token.exchangeCodeForTokens](#tokenexchangecodefortokens) - * [token.enrollAuthenticator](#tokenenrollauthenticatoroptions) * [tokenManager](#tokenmanager-api) * [tokenManager.add](#tokenmanageraddkey-token) * [tokenManager.get](#tokenmanagergetkey) @@ -1079,6 +1079,50 @@ See [authn API](docs/authn.md#unlockaccountoptions). See [authn API](docs/authn.md#verifyrecoverytokenoptions). +#### `enrollAuthenticator(options)` + +> :link: web browser only
+> :hourglass: async + +Enroll authenticators using a redirect to [authorizeUrl](#authorizeurl) with special parameters. After a successful enrollment, the browser will be redirected to the configured [redirectUri](#configuration-options). URL will not contain any tokens. You can use [sdk.handleLoginRedirect](#handleloginredirecttokens-originaluri). + +* `options` - See [Authorize options](#authorize-options) + + Options that will be omitted: `scopes`, `nonce`. + + Options that will be overridden: `responseType: 'none', prompt: 'enroll_authenticator'`. + + ##### `options.enrollAmrValues` - list of [authentication methods](https://self-issued.info/docs/draft-jones-oauth-amr-values-00.html). + + List of AMR values: + | AMR Value | Authenticator | + | ------------- | -------------------- | + | `pwd` | Okta Password | + | `kba` | Security question | + | `email` | Okta Email | + | `sms` | SMS | + | `tel` | Voice call | + | `duo` | DUO | + | `symantec` | Symantec VIP | + | `google_otp` | Google Authenticator | + | `okta_verify` | Okta Verify | + | `pop` | WebAuthn | + | `oath_otp` | On-Prem MFA | + | `rsa` | RSA SecurID | + | `yubikey` | Yubikey | + | `otp` | Custom HOTP | + | `fed` | External IdP | + | `sc` | SmartCard/PIV | + +```javascript +authClient.enrollAuthenticator({ + enrollAmrValues: ['okta_verify'] +}) +.catch(function(err) { + // handle AuthSdkError +}); +``` + ### `webfinger(options)` > :hourglass: async @@ -1316,10 +1360,10 @@ The following configuration options can be included in `token.getWithoutPrompt`, | `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. Special value `enroll_authenticator` is used for [token.enrollAuthenticator](#tokenenrollauthenticatoroptions). | +| `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. Special value `enroll_authenticator` is used for [enrollAuthenticator](#enrollauthenticatoroptions). | | `maxAge` | Allowable elapsed time, in seconds, since the last time the end user was actively authenticated by Okta. | | `acrValues` | [[EA][early-access]] Optional parameter to increase the level of user assurance. See [Predefined ACR values](https://developer.okta.com/docs/guides/step-up-authentication/main/#predefined-parameter-values) for more information. | -| `enrollAmrValues` | List of [authentication methods](https://self-issued.info/docs/draft-jones-oauth-amr-values-00.html) used to enroll authenticators with [token.enrollAuthenticator](#tokenenrollauthenticatoroptions) | +| `enrollAmrValues` | List of [authentication methods](https://self-issued.info/docs/draft-jones-oauth-amr-values-00.html) used to enroll authenticators with [enrollAuthenticator](#enrollauthenticatoroptions) | | `loginHint` | A username to prepopulate if prompting for authentication. | For more details, see Okta's [Authorize Request API](https://developer.okta.com/docs/api/resources/oidc#request-parameters). @@ -1599,49 +1643,6 @@ Returns a `TokenParams` object. If `PKCE` is enabled, this object will contain v Used internally to perform the final step of the `PKCE` authorization code flow. Accepts a `TokenParams` object which should contain a `codeVerifier` and an `authorizationCode`. -#### `token.enrollAuthenticator(options)` - -> :link: web browser only
-> :hourglass: async - -Enroll authenticators using a redirect to [authorizeUrl](#authorizeurl) with special parameters. After a successful enrollment, the browser will be redirected to the configured [redirectUri](#configuration-options). URL will not contain any tokens. You can use [sdk.handleLoginRedirect](#handleloginredirecttokens-originaluri). - -* `options` - See [Authorize options](#authorize-options) - - Options that will be omitted: `scopes`, `nonce`. - - Options that will be overridden: `responseType: 'none', prompt: 'enroll_authenticator'`. - - ##### `options.enrollAmrValues` - list of [authentication methods](https://self-issued.info/docs/draft-jones-oauth-amr-values-00.html). - - List of AMR values: - | AMR Value | Authenticator | - | ------------- | -------------------- | - | `pwd` | Okta Password | - | `kba` | Security question | - | `email` | Okta Email | - | `sms` | SMS | - | `tel` | Voice call | - | `duo` | DUO | - | `symantec` | Symantec VIP | - | `google_otp` | Google Authenticator | - | `okta_verify` | Okta Verify | - | `pop` | WebAuthn | - | `oath_otp` | On-Prem MFA | - | `rsa` | RSA SecurID | - | `yubikey` | Yubikey | - | `otp` | Custom HOTP | - | `fed` | External IdP | - | `sc` | SmartCard/PIV | - -```javascript -authClient.token.enrollAuthenticator({ - enrollAmrValues: ['okta_verify'] -}) -.catch(function(err) { - // handle AuthSdkError -}); -``` ### `tokenManager` API diff --git a/lib/oidc/enrollAuthenticator.ts b/lib/oidc/enrollAuthenticator.ts index 1b7740da7..6c058f037 100644 --- a/lib/oidc/enrollAuthenticator.ts +++ b/lib/oidc/enrollAuthenticator.ts @@ -27,5 +27,5 @@ export async function enrollAuthenticator( const meta = createOAuthMeta(sdk, tokenParams); const requestUrl = meta.urls.authorizeUrl + buildAuthorizeParams(tokenParams); sdk.transactionManager.save(meta); - sdk.token.enrollAuthenticator._setLocation(requestUrl); + sdk.enrollAuthenticator._setLocation(requestUrl); } diff --git a/lib/oidc/factory/api.ts b/lib/oidc/factory/api.ts index 57a4874d9..b7adf0faa 100644 --- a/lib/oidc/factory/api.ts +++ b/lib/oidc/factory/api.ts @@ -18,7 +18,6 @@ import { getUserInfo } from '../getUserInfo'; import { getWithoutPrompt } from '../getWithoutPrompt'; import { getWithPopup } from '../getWithPopup'; import { getWithRedirect } from '../getWithRedirect'; -import { enrollAuthenticator } from '../enrollAuthenticator'; import { parseFromUrl } from '../parseFromUrl'; import { renewToken } from '../renewToken'; import { renewTokens } from '../renewTokens'; @@ -29,8 +28,6 @@ import { CustomUserClaims, GetWithRedirectAPI, GetWithRedirectFunction, - EnrollAuthenticatorAPI, - EnrollAuthenticatorFunction, IDToken, OktaAuthOAuthInterface, ParseFromUrlInterface, @@ -60,12 +57,6 @@ export function createTokenAPI(sdk: OktaAuthOAuthInterface, queue: PromiseQueue) _setLocation }); - const enrollAuthenticatorFn = useQueue(enrollAuthenticator.bind(null, sdk)) as EnrollAuthenticatorFunction; - const enrollAuthenticatorApi: EnrollAuthenticatorAPI = Object.assign(enrollAuthenticatorFn, { - // This is exposed so we can set window.location in our tests - _setLocation - }); - // eslint-disable-next-line max-len const parseFromUrlFn = useQueue(parseFromUrl.bind(null, sdk)) as ParseFromUrlInterface; const parseFromUrlApi: ParseFromUrlInterface = Object.assign(parseFromUrlFn, { @@ -91,7 +82,6 @@ export function createTokenAPI(sdk: OktaAuthOAuthInterface, queue: PromiseQueue) getWithoutPrompt: getWithoutPrompt.bind(null, sdk), getWithPopup: getWithPopup.bind(null, sdk), getWithRedirect: getWithRedirectApi, - enrollAuthenticator: enrollAuthenticatorApi, parseFromUrl: parseFromUrlApi, decode: decodeToken, revoke: revokeToken.bind(null, sdk), diff --git a/lib/oidc/mixin/index.ts b/lib/oidc/mixin/index.ts index 6a274539e..d02be0bbf 100644 --- a/lib/oidc/mixin/index.ts +++ b/lib/oidc/mixin/index.ts @@ -25,11 +25,14 @@ import { TransactionManagerInterface, TransactionManagerConstructor, UserClaims, + EnrollAuthenticatorAPI, + EnrollAuthenticatorFunction, } from '../types'; import PKCE from '../util/pkce'; import { createTokenAPI } from '../factory'; import { TokenManager } from '../TokenManager'; import { getOAuthUrls, isLoginRedirect } from '../util'; +import { enrollAuthenticator } from '../enrollAuthenticator'; import { OktaAuthSessionInterface } from '../../session/types'; import { provideOriginalUri } from './node'; @@ -56,6 +59,7 @@ export function mixinOAuth tokenManager: TokenManager; transactionManager: TM; pkce: PkceAPI; + enrollAuthenticator: EnrollAuthenticatorAPI; _pending: { handleLogin: boolean }; _tokenQueue: PromiseQueue; @@ -81,6 +85,20 @@ export function mixinOAuth // TokenManager this.tokenManager = new TokenManager(this, this.options.tokenManager); + + const _setLocation = (url) => { + if (this.options.setLocation) { + this.options.setLocation(url); + } else { + window.location = url; + } + }; + const enrollAuthenticatorFn = enrollAuthenticator.bind(null, this) as EnrollAuthenticatorFunction; + const enrollAuthenticatorApi: EnrollAuthenticatorAPI = Object.assign(enrollAuthenticatorFn, { + // This is exposed so we can set window.location in our tests + _setLocation + }); + this.enrollAuthenticator = enrollAuthenticatorApi; } // inherited from subclass diff --git a/lib/oidc/types/api.ts b/lib/oidc/types/api.ts index 43644bd47..7d167bd00 100644 --- a/lib/oidc/types/api.ts +++ b/lib/oidc/types/api.ts @@ -78,7 +78,6 @@ export interface TokenAPI extends BaseTokenAPI { idToken?: IDToken ): Promise>; getWithRedirect: GetWithRedirectAPI; - enrollAuthenticator: EnrollAuthenticatorAPI; parseFromUrl: ParseFromUrlInterface; getWithoutPrompt(params?: TokenParams): Promise; getWithPopup(params?: TokenParams): Promise; @@ -161,6 +160,7 @@ export interface OktaAuthOAuthInterface storeTokensFromRedirect(): Promise; getUser(): Promise>; signInWithRedirect(opts?: SigninWithRedirectOptions): Promise; + enrollAuthenticator: EnrollAuthenticatorAPI; revokeAccessToken(accessToken?: AccessToken): Promise; revokeRefreshToken(refreshToken?: RefreshToken): Promise; diff --git a/lib/oidc/util/prepareTokenParams.ts b/lib/oidc/util/prepareTokenParams.ts index 665490dd1..a2640fe27 100644 --- a/lib/oidc/util/prepareTokenParams.ts +++ b/lib/oidc/util/prepareTokenParams.ts @@ -79,7 +79,6 @@ export async function preparePKCE( } function prepareEnrollAuthenticator( - sdk: OktaAuthOAuthInterface, tokenParams: TokenParams ): TokenParams { tokenParams = { @@ -113,7 +112,7 @@ export async function prepareTokenParams( tokenParams = { ...defaults, ...tokenParams }; if (tokenParams.prompt === 'enroll_authenticator') { - tokenParams = prepareEnrollAuthenticator(sdk, tokenParams); + tokenParams = prepareEnrollAuthenticator(tokenParams); } else if (tokenParams.pkce) { tokenParams = await preparePKCE(sdk, tokenParams); } diff --git a/test/apps/app/src/testApp.ts b/test/apps/app/src/testApp.ts index 1fa146478..1891ce743 100644 --- a/test/apps/app/src/testApp.ts +++ b/test/apps/app/src/testApp.ts @@ -894,7 +894,7 @@ class TestApp { state: this.config.state, enrollAmrValues: this.config.enrollAmrValues, }); - return this.oktaAuth.token.enrollAuthenticator(options) + return this.oktaAuth.enrollAuthenticator(options) .catch(e => { this.renderError(e); throw e; diff --git a/test/spec/oidc/enrollAuthenticator.ts b/test/spec/oidc/enrollAuthenticator.ts index 22a0d570a..6ec5c2c01 100644 --- a/test/spec/oidc/enrollAuthenticator.ts +++ b/test/spec/oidc/enrollAuthenticator.ts @@ -31,10 +31,8 @@ describe('enrollAuthenticator', () => { transactionManager: { save: () => {} }, - token: { - enrollAuthenticator: { - _setLocation: () => {} - } + enrollAuthenticator: { + _setLocation: () => {} } }; const tokenParams = { @@ -96,10 +94,10 @@ describe('enrollAuthenticator', () => { it('redirects to the authorize endpoint', async () => { const { sdk, tokenParams, enrollParams, authorizeParams } = testContext; - jest.spyOn(sdk.token.enrollAuthenticator, '_setLocation'); + jest.spyOn(sdk.enrollAuthenticator, '_setLocation'); await enrollAuthenticator(sdk, enrollParams); expect(mocked.authorize.buildAuthorizeParams).toHaveBeenCalledWith(tokenParams); - expect(sdk.token.enrollAuthenticator._setLocation).toHaveBeenCalledWith(`http://fake-authorize${authorizeParams}`); + expect(sdk.enrollAuthenticator._setLocation).toHaveBeenCalledWith(`http://fake-authorize${authorizeParams}`); }); }); \ No newline at end of file diff --git a/test/types/token.test-d.ts b/test/types/token.test-d.ts index 7717ba9ab..d998c73e1 100644 --- a/test/types/token.test-d.ts +++ b/test/types/token.test-d.ts @@ -94,13 +94,13 @@ const tokens = { enrollAmrValues: 'email', responseType: 'none' }; - expectType(await authClient.token.enrollAuthenticator(enrollAuthenticatorOptons)); - expectType(await authClient.token.enrollAuthenticator(enrollAuthenticatorOptons2)); + expectType(await authClient.enrollAuthenticator(enrollAuthenticatorOptons)); + expectType(await authClient.enrollAuthenticator(enrollAuthenticatorOptons2)); expectError(async () => { - await authClient.token.enrollAuthenticator({}); + await authClient.enrollAuthenticator({}); }); expectError(async () => { - await authClient.token.enrollAuthenticator(); + await authClient.enrollAuthenticator(); }); const customUrls = {