Skip to content

Commit

Permalink
moved enrollAuthenticator to top level
Browse files Browse the repository at this point in the history
  • Loading branch information
denysoblohin-okta committed Oct 24, 2022
1 parent 876dd5e commit c7f698e
Show file tree
Hide file tree
Showing 9 changed files with 77 additions and 71 deletions.
93 changes: 47 additions & 46 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -1079,6 +1079,50 @@ See [authn API](docs/authn.md#unlockaccountoptions).

See [authn API](docs/authn.md#verifyrecoverytokenoptions).

#### `enrollAuthenticator(options)`

> :link: web browser only <br>
> :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
Expand Down Expand Up @@ -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).
Expand Down Expand Up @@ -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 <br>
> :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

Expand Down
2 changes: 1 addition & 1 deletion lib/oidc/enrollAuthenticator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
10 changes: 0 additions & 10 deletions lib/oidc/factory/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand All @@ -29,8 +28,6 @@ import {
CustomUserClaims,
GetWithRedirectAPI,
GetWithRedirectFunction,
EnrollAuthenticatorAPI,
EnrollAuthenticatorFunction,
IDToken,
OktaAuthOAuthInterface,
ParseFromUrlInterface,
Expand Down Expand Up @@ -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, {
Expand All @@ -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),
Expand Down
18 changes: 18 additions & 0 deletions lib/oidc/mixin/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand All @@ -56,6 +59,7 @@ export function mixinOAuth
tokenManager: TokenManager;
transactionManager: TM;
pkce: PkceAPI;
enrollAuthenticator: EnrollAuthenticatorAPI;

_pending: { handleLogin: boolean };
_tokenQueue: PromiseQueue;
Expand All @@ -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
Expand Down
2 changes: 1 addition & 1 deletion lib/oidc/types/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,6 @@ export interface TokenAPI extends BaseTokenAPI {
idToken?: IDToken
): Promise<UserClaims<S>>;
getWithRedirect: GetWithRedirectAPI;
enrollAuthenticator: EnrollAuthenticatorAPI;
parseFromUrl: ParseFromUrlInterface;
getWithoutPrompt(params?: TokenParams): Promise<TokenResponse>;
getWithPopup(params?: TokenParams): Promise<TokenResponse>;
Expand Down Expand Up @@ -161,6 +160,7 @@ export interface OktaAuthOAuthInterface
storeTokensFromRedirect(): Promise<void>;
getUser<T extends CustomUserClaims = CustomUserClaims>(): Promise<UserClaims<T>>;
signInWithRedirect(opts?: SigninWithRedirectOptions): Promise<void>;
enrollAuthenticator: EnrollAuthenticatorAPI;

revokeAccessToken(accessToken?: AccessToken): Promise<unknown>;
revokeRefreshToken(refreshToken?: RefreshToken): Promise<unknown>;
Expand Down
3 changes: 1 addition & 2 deletions lib/oidc/util/prepareTokenParams.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,6 @@ export async function preparePKCE(
}

function prepareEnrollAuthenticator(
sdk: OktaAuthOAuthInterface,
tokenParams: TokenParams
): TokenParams {
tokenParams = {
Expand Down Expand Up @@ -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);
}
Expand Down
2 changes: 1 addition & 1 deletion test/apps/app/src/testApp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
10 changes: 4 additions & 6 deletions test/spec/oidc/enrollAuthenticator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,8 @@ describe('enrollAuthenticator', () => {
transactionManager: {
save: () => {}
},
token: {
enrollAuthenticator: {
_setLocation: () => {}
}
enrollAuthenticator: {
_setLocation: () => {}
}
};
const tokenParams = {
Expand Down Expand Up @@ -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}`);
});

});
8 changes: 4 additions & 4 deletions test/types/token.test-d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -94,13 +94,13 @@ const tokens = {
enrollAmrValues: 'email',
responseType: 'none'
};
expectType<void>(await authClient.token.enrollAuthenticator(enrollAuthenticatorOptons));
expectType<void>(await authClient.token.enrollAuthenticator(enrollAuthenticatorOptons2));
expectType<void>(await authClient.enrollAuthenticator(enrollAuthenticatorOptons));
expectType<void>(await authClient.enrollAuthenticator(enrollAuthenticatorOptons2));
expectError(async () => {
await authClient.token.enrollAuthenticator({});
await authClient.enrollAuthenticator({});
});
expectError(async () => {
await authClient.token.enrollAuthenticator();
await authClient.enrollAuthenticator();
});

const customUrls = {
Expand Down

0 comments on commit c7f698e

Please sign in to comment.