From 235c4f6fcc23492833e96ca1860e52cdc4cf6c34 Mon Sep 17 00:00:00 2001 From: pamapa Date: Wed, 15 Nov 2023 13:57:04 +0100 Subject: [PATCH 1/2] doc: improve documentation --- README.md | 9 ++-- docs/index.md | 37 ++++++++------- docs/migration.md | 14 ++++-- .../authorization-code-grant-with-pkce.md | 37 +++++++++++++++ docs/protocols/authorization-code-grant.md | 46 +++++++++++++++++++ docs/protocols/refresh-token-grant.md | 23 ++++++++++ ...ource-owner-password-credentials-grant.md} | 39 ++++++++++++++-- .../silent-refresh-token-in-iframe-flow.md | 43 +++++++++++++++++ 8 files changed, 218 insertions(+), 30 deletions(-) create mode 100644 docs/protocols/authorization-code-grant-with-pkce.md create mode 100644 docs/protocols/authorization-code-grant.md create mode 100644 docs/protocols/refresh-token-grant.md rename docs/{ropc.md => protocols/resource-owner-password-credentials-grant.md} (50%) create mode 100644 docs/protocols/silent-refresh-token-in-iframe-flow.md diff --git a/README.md b/README.md index c1db3e7db..f519db047 100644 --- a/README.md +++ b/README.md @@ -22,10 +22,11 @@ available [here](docs/migration.md). Implements the following OAuth 2.0 protocols and supports [OpenID Connect Core 1.0](https://openid.net/specs/openid-connect-core-1_0.html): -- [Authorization Code Grant](https://oauth.net/2/grant-types/authorization-code/) - with [PKCE](https://oauth.net/2/pkce/) -- [Resource Owner Password Credentials Grant](https://www.rfc-editor.org/rfc/rfc6749#section-1.3.3); however, read the [security concerns](docs/ropc.md) before using this flow -- [Refresh Token Grant](https://oauth.net/2/grant-types/refresh-token/) +- [Authorization Code Grant with Proof Key for Code Exchange (PKCE)](docs/protocols/authorization-code-grant-with-pkce.md) +- [Authorization Code Grant](docs/protocols/authorization-code-grant.md) +- [Resource Owner Password Credentials (ROPC) Grant](docs/protocols/resource-owner-password-credentials-grant.md) +- [Refresh Token Grant](docs/protocols/refresh-token-grant.md) +- [Silent Refresh Token in iframe Flow](docs/protocols/silent-refresh-token-in-iframe-flow.md) ## Table of Contents diff --git a/docs/index.md b/docs/index.md index 6934ef5a0..348c13a61 100644 --- a/docs/index.md +++ b/docs/index.md @@ -15,18 +15,25 @@ with you use to use the library: The remainder of this document will primarily focus on the [UserManager](classes/UserManager.html). -## UserManager -### Configuration +# Principle of function +To understand how to use this library see here: +- [Authorization Code Grant with Proof Key for Code Exchange (PKCE)](https://github.com/authts/oidc-client-ts/blob/main/docs/protocols/authorization-code-grant-with-pkce.md) +- [Authorization Code Grant](https://github.com/authts/oidc-client-ts/blob/main/docs/protocols/authorization-code-grant.md) +- [Resource Owner Password Credentials (ROPC) Grant](https://github.com/authts/oidc-client-ts/blob/main/docs/protocols/resource-owner-password-credentials-grant.md) +- [Refresh Token Grant](https://github.com/authts/oidc-client-ts/blob/main/docs/protocols/refresh-token-grant.md) +- [Silent Refresh Token in iframe Flow](https://github.com/authts/oidc-client-ts/blob/main/docs/protocols/silent-refresh-token-in-iframe-flow.md) +# UserManager + +## Configuration The [UserManager](classes/UserManager.html) constructor requires a settings object as a parameter: - [UserManagerSettings](interfaces/UserManagerSettings.html) which extends - [OidcClientSettings](interfaces/OidcClientSettings.html) -#### Required settings - +### Required settings - [authority](interfaces/OidcClientSettings.html#authority): The URL of the OIDC/OAuth2 provider. - [client_id](interfaces/OidcClientSettings.html#client_id): Your client @@ -35,8 +42,7 @@ object as a parameter: URI of your client application to receive a response from the OIDC/OAuth2 provider. -#### Provider settings if CORS not supported on OIDC/OAuth2 provider metadata endpoint - +### Provider settings if CORS not supported on OIDC/OAuth2 provider metadata endpoint The [authority](interfaces/OidcClientSettings.html#authority) URL setting is used to make HTTP requests to discover more information about the OIDC/OAuth2 provider and populate a `metadata` property on the settings. If the server does @@ -52,8 +58,7 @@ provider: - [metadataSeed](interfaces/UserManagerSettings.html#metadataSeed) can be used to seed or add additional values to the results of the discovery request. -### Events - +## Events The [UserManager](classes/UserManager.html) will raise various events about the user's session: @@ -71,11 +76,11 @@ mgr.events.addAccessTokenExpiring(function() { }); ``` -## User +# User The [User](classes/User.html) type is returned from the [UserManager](classes/UserManager.html)'s [getUser](classes/UserManager.html#getUser) API. -## Logging +# Logging The oidc-client-ts library supports logging. You can set a logger by assigning `Oidc.Log.logger` to anything that supports a `info`, `warn`, and `error` methods that accept a params array. By default, no logger is configured. The `console` object in the browser supports these, so a common way to easily @@ -89,7 +94,7 @@ Also, logging has levels so you can control the verbosity by calling `Oidc.Log.setLevel()` with one of `Oidc.Log.NONE`, `Oidc.Log.ERROR`, `Oidc.Log.WARN`, or `Oidc.Log.INFO`. The default is `Oidc.Log.INFO`. -## Provider specific settings +# Provider specific settings Additional provider specific settings may be needed for a flawless operation: **Amazon Cognito** @@ -104,7 +109,7 @@ const mgr = new UserManager({ ``` -## Custom state in user object +# Custom state in user object In case you would like to add additional data into the [User](classes/User.html) object, you can do so during the initial sign-in request. ```javascript @@ -117,7 +122,7 @@ After successful sign-in the custom state is part of the [User](classes/User.htm This custom state should not be confused with the URL state parameter. The latter is internally used to match against the authentication state object to finish the authentication process. -## Custom state in request url +# Custom state in request url If you would like to encode a custom state string in the sign in request url, you can do so with the `url_state` parameter. You may want to do this in order to pass user state to the authentication server and/or a proxy and return that state as part of the response. ```javascript @@ -128,13 +133,13 @@ mgr.signinRedirect({ url_state: 'custom url state' }) The `url_state` will be appended to the opaque, unique value created by the library when sending the request. It should survive the round trip to your authentication server and will be part of the [User](classes/User.html#url_state) object as `url_state`. -## Projects using oidc-client +# Projects using oidc-client-ts - [React context provider](https://github.com/authts/react-oidc-context) - [Angular sample](https://github.com/authts/sample-angular-oidc-client-ts) - [Chrome service worker](https://github.com/Alino/OIDC-client-ts-chromium-sample) -## Training +# Training -- [Securing Angular Apps with OpenID and OAuth2](https://noyes.me/ng-openid-oauth2) +- [Securing Angular Apps with OpenID Connect and OAuth2](https://www.pluralsight.com/courses/openid-and-oauth2-securing-angular-apps) diff --git a/docs/migration.md b/docs/migration.md index 991ca6c19..dd8046bdf 100644 --- a/docs/migration.md +++ b/docs/migration.md @@ -1,15 +1,19 @@ ## oidc-client-ts v2.4.0 → oidc-client-ts v3.0.0 -The API is largely backwards-compatible. The merge claims behavior has been improved. +The API is largely backwards-compatible. + +The "crypto-js" software library has been removed; the native crypto/crypto.subtle module built into the browser is instead used. All modern browser are expected to support it. If need to support older browsers stay with v2.4! + +The behavior of merging claims has been improved. ### [OidcClientSettings](https://authts.github.io/oidc-client-ts/interfaces/OidcClientSettings.html) - the following deprecated properties were **removed**: - - `clockSkewInSeconds` unused since 2.0.0 - - `userInfoJwtIssuer` unused since 2.0.0 - - `refreshTokenCredentials` use `fetchRequestCredentials` since 2.1.0 + - `clockSkewInSeconds` + - `userInfoJwtIssuer` + - `refreshTokenCredentials` use `fetchRequestCredentials` - the `mergeClaims` has been replaced by `mergeClaimsStrategy` - - if the previous behavior is needed `mergeClaimsStrategy: { array: "merge" }` can be used + - if the previous behavior is required `mergeClaimsStrategy: { array: "merge" }` comes close to it - default of `response_mode` changed from `query` → `undefined` diff --git a/docs/protocols/authorization-code-grant-with-pkce.md b/docs/protocols/authorization-code-grant-with-pkce.md new file mode 100644 index 000000000..a1752c612 --- /dev/null +++ b/docs/protocols/authorization-code-grant-with-pkce.md @@ -0,0 +1,37 @@ +# Authorization Code Grant with Proof Key for Code Exchange (PKCE) + +The authorization code protocol is part of OAuth 2.0 (defined in [OAuth 2.0 RFC 7636](https://tools.ietf.org/html/rfc7636)). It involves the exchange of an authorization code for a token. This is the recommend authorization code flow in the [OAuth 2.1 draft](https://datatracker.ietf.org/doc/html/draft-ietf-oauth-v2-1-07#section-10). + + +## Principle of function +```mermaid +--- +title: Authorization Code Grant with Proof Key for Code Exchange (PKCE) +--- +sequenceDiagram + actor User + User->>App: Click sign-in link (1) + + activate App + Note left of App: Generate code_verifier and
code_challenge + App->>Identity Provider: Authorization code request & code_challenge (2) + deactivate App + + Identity Provider-->>User: Redirect to login/authorization prompt (3) + User-->>Identity Provider: Authenticate (3) + Identity Provider->>App: Authorization code (3) + + activate App + App->>Identity Provider: Authorization code & code verifier (4) + Note right of Identity Provider: Validate authorization code &
code_verifier + Identity Provider->>App: Access token and ID token (4) + deactivate App + + App->>Your API: Request protected data with access token (5) +``` + +1. The user clicks sign-in within the application. +2. `signinRedirect()` or `signinPopup()` must be used to start the flow. +3. The identity provider authenticates the user and stores the code_challenge and redirects the user back to the application with an authorization code. +4. `signinCallback()` handles this callback by sending this authorization code and code_verifier to the identity provider and receiving in return the access token and ID token. +5. The access token is now accessible via `getUser()?.access_token` and inserted into the requests to your protected API. diff --git a/docs/protocols/authorization-code-grant.md b/docs/protocols/authorization-code-grant.md new file mode 100644 index 000000000..bb66cd330 --- /dev/null +++ b/docs/protocols/authorization-code-grant.md @@ -0,0 +1,46 @@ +# Authorization Code Grant + +The authorization code protocol is part of OAuth 2.0 defined in ([OAuth 2.0 RFC 6749, section 4.1](https://tools.ietf.org/html/rfc6749#section-4.1)). It involves the exchange of an authorization code for a token. + +**NOTE**
+It implies some security risks, so you should only use it after a security assessment. + + +## Security concerns +This flow can only be used for applications, which can protected the client secret: +- **Native app**: Can not securely store the client secret, as its possible to decompile the application. +- **Single-page app**: Can not securely store the client secret, as the full code is exposed in the users browser + +In that scenarios [Authorization Code Grant with Proof Key for Code Exchange (PKCE)](authorization-code-flow-with-pkce.md) must be used. + + +## Principle of function +```mermaid +--- +title: Authorization Code Grant +--- +sequenceDiagram + actor User + User->>App: Click sign-in link (1) + activate App + App->>Identity Provider: Authorization code request (2) + deactivate App + + Identity Provider-->>User: Redirect to login/authorization prompt (3) + User-->>Identity Provider: Authenticate (3) + Identity Provider->>App: Authorization code (3) + + activate App + App->>Identity Provider: Authorization code & client secret (4) + Note right of Identity Provider: Validate authorization code &
client secret + Identity Provider->>App: Access token and ID token (4) + deactivate App + + App->>Your API: Request protected data with access token (5) +``` + +1. The user clicks sign-in within the application. +2. `signinRedirect()` or `signinPopup()` must be used to start the flow. +3. The identity provider authenticates the user and stores the code_challenge and redirects the user back to the application with an authorization code. +4. `signinCallback()` handles this callback by sending this authorization code and client secret to the identity provider and receiving in return the access token and ID token. +5. The access token is now accessible via `getUser()?.access_token` and inserted into the requests to your protected API. diff --git a/docs/protocols/refresh-token-grant.md b/docs/protocols/refresh-token-grant.md new file mode 100644 index 000000000..d63ce218e --- /dev/null +++ b/docs/protocols/refresh-token-grant.md @@ -0,0 +1,23 @@ +# Refresh Token Grant + +This protocol is part of OAuth 2.0 (defined in [OAuth 2.0 RFC 6749, section 1.5](https://tools.ietf.org/html/rfc6749#section-1.5)). +The refresh token grant is used by clients to exchange a refresh token for an access token when the access token has expired. + + +## Principle of function +```mermaid +--- +title: Refresh Token Grant +--- +sequenceDiagram + App->>Identity Provider: Request new access token with refresh token (1) + activate App + Note right of Identity Provider: Validate refresh token + Identity Provider->>App: Access token and optional refresh token (1) + deactivate App + + App->>Your API: Request protected data with refreshed access token (2) +``` + +1. `signinSilent()` must be used to start the flow. +2. The refreshed access token is now accessible via `getUser()?.access_token` and inserted into the requests to your protected API. diff --git a/docs/ropc.md b/docs/protocols/resource-owner-password-credentials-grant.md similarity index 50% rename from docs/ropc.md rename to docs/protocols/resource-owner-password-credentials-grant.md index 5f5314f58..e95777260 100644 --- a/docs/ropc.md +++ b/docs/protocols/resource-owner-password-credentials-grant.md @@ -1,13 +1,42 @@ -## Security concerns on Resource Owner Password Credentials flow +# Resource Owner Password Credentials (ROPC) Grant -This OAuth 2.0 flow implies some security risks, so you should only use it after a security assesment. +This protocol is part of OAuth 2.0 (defined in [OAuth 2.0 RFC 6749, section 4.3](https://www.rfc-editor.org/rfc/rfc6749#section-4.3)). -To start with, this flow is not part of the [Open ID Connect standard](https://openid.net/specs/openid-connect-core-1_0.html). Furthermore, although it is part of [OAuth 2.0](https://www.rfc-editor.org/rfc/rfc6749#section-4.3), it has been removed in the [OAuth 2.1 draft](https://datatracker.ietf.org/doc/html/draft-ietf-oauth-v2-1-07#section-10), and there are good reasons for this: +**NOTE**
+It implies some security risks, so you should only use it after a security assessment. + + +## Security concerns + +To start with, this flow is not part of the [Open ID Connect standard](https://openid.net/specs/openid-connect-core-1_0.html). Furthermore, although it is part of OAuth 2.0, it has been removed in the [OAuth 2.1 draft](https://datatracker.ietf.org/doc/html/draft-ietf-oauth-v2-1-07#section-10), and there are good reasons for this: * When using this flow, the credentials of the user are exposed to the client application. The RFC mandates that ["the client application MUST discard the credentials once the access token has been obtained"](https://www.rfc-editor.org/rfc/rfc6749#section-4.3.1), but there is no technical way for the Identity Provider / Authorization Server to enforce this point. This flow MUST NOT be allowed unless the Client can be enforced to fulfill this requirement through other means (probably because both are under the same security domain, probably the same organization or similar constraints). This point is covered [several](https://www.rfc-editor.org/rfc/rfc6749#section-1.3.3) [times](https://www.rfc-editor.org/rfc/rfc6749#section-4.3) during the RFC and by some IdP implementations, such as [Auth0](https://auth0.com/docs/get-started/authentication-and-authorization-flow/resource-owner-password-flow) or [Keycloak](https://www.keycloak.org/docs/latest/securing_apps/#_resource_owner_password_credentials_flow), but it is sometimes quickly ignored by some developers. -* Even if the previous point is covered, this flow is increasing the attack surface of the system. For example, if the Client Application is compromised (maybe through an XSS attack, for example), the credentials of the user are exposed, so the attacker have access to other applications accessible by the user. In comparison, for example, in the Authorization Code Flow if the Client Application is equaly compromised only the access token is exposed, usually meaning that only the given application has been compromised. A different way to see this is: usually the IdP/Authorization Server are strongly protected, and the Client Applications are allowed lower levels of security auditing... but when using this flow, if any of them is exposed, the user credentials are exposed; so both of them should be equaly treated regarding security. +* Even if the previous point is covered, this flow is increasing the attack surface of the system. For example, if the Client Application is compromised (maybe through an XSS attack, for example), the credentials of the user are exposed, so the attacker have access to other applications accessible by the user. In comparison, for example, in the Authorization Code Flow if the Client Application is equally compromised only the access token is exposed, usually meaning that only the given application has been compromised. A different way to see this is: usually the IdP/Authorization Server are strongly protected, and the Client Applications are allowed lower levels of security auditing... but when using this flow, if any of them is exposed, the user credentials are exposed; so both of them should be equally treated regarding security. Therefor, this flow MUST NOT be used as a replacement for the Authorization Code flow. This flow can only be seen as a replacement of classic form-based user/password authentication directly in the application. -Then, why are we adding this support in `oidc-client-ts`? Well... form-based user/password authentication is actually widely used in the industry, and using a standard IdP as authenticator for this architecture has some benefits (other things, such as password expiration, user management backoffice, etc are provided for free by the IdP). So this flow can be an easy help in this scenario. But you MUST NOT use this flow believing that you are having all the security benefits of OpenId Connect or OAuth; you are not. +Then, why are we adding this support in `oidc-client-ts`? Well... form-based user/password authentication is actually widely used in the industry, and using a standard IdP as authenticator for this architecture has some benefits (other things, such as password expiration, user management back-office, etc are provided for free by the IdP). So this flow can be an easy help in this scenario. But you MUST NOT use this flow believing that you are having all the security benefits of OpenId Connect or OAuth; you are not. + + +## Principle of function +```mermaid +--- +title: Resource Owner Password Credentials (ROPC) Grant +--- +sequenceDiagram + actor User + User->>App: Click sign-in link (1) + + activate App + App->>Identity Provider: Authenticate with username and password (2) + Note right of Identity Provider: Validate username &
password + Identity Provider->>App: Access token and ID token (2) + deactivate App + + App->>Your API: Request protected data with access token (3) +``` + +1. The user clicks sign-in within the application. +2. `signinResourceOwnerCredentials()` must be used to start the flow. +3. The access token is now accessible via `getUser()?.access_token` and inserted into the requests to your protected API. diff --git a/docs/protocols/silent-refresh-token-in-iframe-flow.md b/docs/protocols/silent-refresh-token-in-iframe-flow.md new file mode 100644 index 000000000..c44effdb1 --- /dev/null +++ b/docs/protocols/silent-refresh-token-in-iframe-flow.md @@ -0,0 +1,43 @@ +# Silent Refresh Token in iframe Flow + +This flow is using the OAuth2.0 [Authorization Code Grant with Proof Key for Code Exchange (PKCE)](https://github.com/authts/oidc-client-ts/blob/main/docs/protocols/authorization-code-grant-with-pkce.md) or [Authorization Code Grant](https://github.com/authts/oidc-client-ts/blob/main/docs/protocols/authorization-code-grant.md) grants. + +Difference: To silently refresh the token, the server callback is handled in a hidden iframe and not in the main browsing window. + +Running this flow in an iframe succeeds when the user has an authenticated session with the identity provider. +The identity provider is storing a session cookie during the initial authentication. This cookie must be accessible for this flow to work. + + +## Principle of function +```mermaid +--- +title: Silent Refresh Token in iframe Flow +--- +sequenceDiagram + App->>Hidden iframe: Load silent
Authorization Code Grant
in an iframe (1) + + activate Hidden iframe + Note left of Hidden iframe: PKCE: Generate code_verifier and
code_challenge + Hidden iframe->>Identity Provider: Authorization code request (1) + deactivate Hidden iframe + Note right of Hidden iframe: PKCE: with code_challenge + Note right of Identity Provider: Validate session cookie + + Identity Provider->>Hidden iframe: Authorization code (2) + activate Hidden iframe + Hidden iframe->>App: Notify parent window (3) + deactivate Hidden iframe + + activate App + App->>Identity Provider: Authorization code & code verifier or client secret (3) + Note right of Identity Provider: Validate authorization code &
code verifier or client secret + Identity Provider->>App: Access token and ID token (3) + deactivate App + + App->>Your API: Request protected data with refreshed access token (4) +``` + +1. `signinSilent()` must be used to start the flow. +2. The identity provider knows the user already by using the session cookie and redirects the user back to the application with an authorization code. +3. `signinCallback()` handles this callback by sending this authorization code and code_verifier (PKCE) or client secret to the identity provider and receiving in return the access token and ID token. +4. The access token is now accessible via `getUser()?.access_token` and inserted into the requests to your protected API. From 77550139f90b881b5cba264a3a48059aeb9310a2 Mon Sep 17 00:00:00 2001 From: pamapa Date: Thu, 16 Nov 2023 16:31:50 +0100 Subject: [PATCH 2/2] doc: improve code documentation --- docs/oidc-client-ts.api.md | 2 - src/OidcClientSettings.ts | 4 +- src/User.ts | 1 + src/UserManager.ts | 122 +++++++++++++++++++++++++++++------- src/errors/ErrorResponse.ts | 3 +- src/navigators/IWindow.ts | 1 + src/utils/PopupUtils.ts | 2 +- 7 files changed, 104 insertions(+), 31 deletions(-) diff --git a/docs/oidc-client-ts.api.md b/docs/oidc-client-ts.api.md index 3d3ad94f7..2336bf188 100644 --- a/docs/oidc-client-ts.api.md +++ b/docs/oidc-client-ts.api.md @@ -969,7 +969,6 @@ export class UserManager { readonly settings: UserManagerSettingsStore; // (undocumented) protected _signin(args: CreateSigninRequestArgs, handle: IWindow, verifySub?: string): Promise; - // (undocumented) signinCallback(url?: string): Promise; // (undocumented) protected _signinEnd(url: string, verifySub?: string): Promise; @@ -984,7 +983,6 @@ export class UserManager { protected _signinStart(args: CreateSigninRequestArgs, handle: IWindow): Promise; // (undocumented) protected _signout(args: CreateSignoutRequestArgs, handle: IWindow): Promise; - // (undocumented) signoutCallback(url?: string, keepOpen?: boolean): Promise; // (undocumented) protected _signoutEnd(url: string): Promise; diff --git a/src/OidcClientSettings.ts b/src/OidcClientSettings.ts index 686809c7e..5e915ef1a 100644 --- a/src/OidcClientSettings.ts +++ b/src/OidcClientSettings.ts @@ -124,7 +124,7 @@ export interface OidcClientSettings { */ revokeTokenAdditionalContentTypes?: string[]; /** - * Will disable pkce validation, changing to true will not append to sign in request code_challenge and code_challenge_method. (default: false) + * Will disable PKCE validation, changing to true will not append to sign in request code_challenge and code_challenge_method. (default: false) */ disablePKCE?: boolean; /** @@ -141,9 +141,9 @@ export interface OidcClientSettings { /** * The settings with defaults applied of the {@link OidcClient}. - * @see {@link OidcClientSettings} * * @public + * @see {@link OidcClientSettings} */ export class OidcClientSettingsStore { // metadata diff --git a/src/User.ts b/src/User.ts index f1f4d1f51..67a07c9cf 100644 --- a/src/User.ts +++ b/src/User.ts @@ -6,6 +6,7 @@ import type { IdTokenClaims } from "./Claims"; /** * Holds claims represented by a combination of the `id_token` and the user info endpoint. + * * @public */ export type UserProfile = IdTokenClaims; diff --git a/src/UserManager.ts b/src/UserManager.ts index 22ebea647..7a8334dcb 100644 --- a/src/UserManager.ts +++ b/src/UserManager.ts @@ -71,13 +71,13 @@ export type SignoutPopupArgs = PopupWindowParams & ExtraSignoutRequestArgs; export type SignoutSilentArgs = IFrameWindowParams & ExtraSignoutRequestArgs; /** - * Provides a higher level API for signing a user in, signing out, managing the user's claims returned from the OIDC provider, - * and managing an access token returned from the OIDC/OAuth2 provider. + * Provides a higher level API for signing a user in, signing out, managing the user's claims returned from the identity provider, + * and managing an access token returned from the identity provider (OAuth2/OIDC). * * @public */ export class UserManager { - /** Returns the settings used to configure the `UserManager`. */ + /** Get the settings used to configure the `UserManager`. */ public readonly settings: UserManagerSettingsStore; protected readonly _logger = new Logger("UserManager"); @@ -113,18 +113,24 @@ export class UserManager { } - /** Returns an object used to register for events raised by the `UserManager`. */ + /** + * Get object used to register for events raised by the `UserManager`. + */ public get events(): UserManagerEvents { return this._events; } - /** Returns an object used to access the metadata configuration of the OIDC provider. */ + /** + * Get object used to access the metadata configuration of the identity provider. + */ public get metadataService(): MetadataService { return this._client.metadataService; } /** - * Returns promise to load the `User` object for the currently authenticated user. + * Load the `User` object for the currently authenticated user. + * + * @returns A promise */ public async getUser(): Promise { const logger = this._logger.create("getUser"); @@ -140,7 +146,9 @@ export class UserManager { } /** - * Returns promise to remove from any storage the currently authenticated user. + * Remove from any storage the currently authenticated user. + * + * @returns A promise */ public async removeUser(): Promise { const logger = this._logger.create("removeUser"); @@ -150,7 +158,11 @@ export class UserManager { } /** - * Returns promise to trigger a redirect of the current window to the authorization endpoint. + * Trigger a redirect of the current window to the authorization endpoint. + * + * @returns A promise + * + * @throws `Error` In cases of wrong authentication. */ public async signinRedirect(args: SigninRedirectArgs = {}): Promise { this._logger.create("signinRedirect"); @@ -166,7 +178,12 @@ export class UserManager { } /** - * Returns promise to process response from the authorization endpoint. The result of the promise is the authenticated `User`. + * Process the response (callback) from the authorization endpoint. + * It is recommend to use {@link UserManager.signinCallback} instead. + * + * @returns A promise containing the authenticated `User`. + * + * @see {@link UserManager.signinCallback} */ public async signinRedirectCallback(url = window.location.href): Promise { const logger = this._logger.create("signinRedirectCallback"); @@ -182,15 +199,16 @@ export class UserManager { } /** - * Returns promise to process the signin with user/password. The result of the promise is the authenticated `User`. + * Trigger the signin with user/password. * - * Throws an ErrorResponse in case of wrong authentication. + * @returns A promise containing the authenticated `User`. + * @throws {@link ErrorResponse} In cases of wrong authentication. */ public async signinResourceOwnerCredentials({ username, password, skipUserInfo = false, - }: SigninResourceOwnerCredentialsArgs ) { + }: SigninResourceOwnerCredentialsArgs): Promise { const logger = this._logger.create("signinResourceOwnerCredential"); const signinResponse = await this._client.processResourceOwnerPasswordCredentials({ username, password, skipUserInfo, extraTokenParams: this.settings.extraTokenParams }); @@ -206,7 +224,10 @@ export class UserManager { } /** - * Returns promise to trigger a request (via a popup window) to the authorization endpoint. The result of the promise is the authenticated `User`. + * Trigger a request (via a popup window) to the authorization endpoint. + * + * @returns A promise containing the authenticated `User`. + * @throws `Error` In cases of wrong authentication. */ public async signinPopup(args: SigninPopupArgs = {}): Promise { const logger = this._logger.create("signinPopup"); @@ -239,7 +260,12 @@ export class UserManager { return user; } /** - * Returns promise to notify the opening window of response from the authorization endpoint. + * Notify the opening window of response (callback) from the authorization endpoint. + * It is recommend to use {@link UserManager.signinCallback} instead. + * + * @returns A promise + * + * @see {@link UserManager.signinCallback} */ public async signinPopupCallback(url = window.location.href, keepOpen = false): Promise { const logger = this._logger.create("signinPopupCallback"); @@ -248,8 +274,9 @@ export class UserManager { } /** - * Returns promise to trigger a silent request (via an iframe) to the authorization endpoint. - * The result of the promise is the authenticated `User`. + * Trigger a silent request (via refresh token or an iframe) to the authorization endpoint. + * + * @returns A promise that contains the authenticated `User`. */ public async signinSilent(args: SigninSilentArgs = {}): Promise { const logger = this._logger.create("signinSilent"); @@ -310,7 +337,13 @@ export class UserManager { } /** - * Returns promise to notify the parent window of response from the authorization endpoint. + * + * Notify the parent window of response (callback) from the authorization endpoint. + * It is recommend to use {@link UserManager.signinCallback} instead. + * + * @returns A promise + * + * @see {@link UserManager.signinCallback} */ public async signinSilentCallback(url = window.location.href): Promise { const logger = this._logger.create("signinSilentCallback"); @@ -318,6 +351,15 @@ export class UserManager { logger.info("success"); } + /** + * Process any response (callback) from the authorization endpoint, by dispatching the request_type + * and executing one of the following functions: + * - {@link UserManager.signinRedirectCallback} + * - {@link UserManager.signinPopupCallback} + * - {@link UserManager.signinSilentCallback} + * + * @throws `Error` If request_type is unknown or signout can not processed. + */ public async signinCallback(url = window.location.href): Promise { const { state } = await this._client.readSigninResponseState(url); switch (state.request_type) { @@ -332,6 +374,15 @@ export class UserManager { } } + /** + * Process any response (callback) from the end session endpoint, by dispatching the request_type + * and executing one of the following functions: + * - {@link UserManager.signoutRedirectCallback} + * - {@link UserManager.signoutPopupCallback} + * - {@link UserManager.signoutSilentCallback} + * + * @throws `Error` If request_type is unknown or signout can not processed. + */ public async signoutCallback(url = window.location.href, keepOpen = false): Promise { const { state } = await this._client.readSignoutResponseState(url); if (!state) { @@ -354,7 +405,9 @@ export class UserManager { } /** - * Returns promise to query OP for user's current signin status. Returns object with session_state and subject identifier. + * Query OP for user's current signin status. + * + * @returns A promise object with session_state and subject identifier. */ public async querySessionStatus(args: QuerySessionStatusArgs = {}): Promise { const logger = this._logger.create("querySessionStatus"); @@ -464,7 +517,9 @@ export class UserManager { } /** - * Returns promise to trigger a redirect of the current window to the end session endpoint. + * Trigger a redirect of the current window to the end session endpoint. + * + * @returns A promise */ public async signoutRedirect(args: SignoutRedirectArgs = {}): Promise { const logger = this._logger.create("signoutRedirect"); @@ -482,7 +537,12 @@ export class UserManager { } /** - * Returns promise to process response from the end session endpoint. + * Process response (callback) from the end session endpoint. + * It is recommend to use {@link UserManager.signoutCallback} instead. + * + * @returns A promise containing signout response + * + * @see {@link UserManager.signoutCallback} */ public async signoutRedirectCallback(url = window.location.href): Promise { const logger = this._logger.create("signoutRedirectCallback"); @@ -492,7 +552,9 @@ export class UserManager { } /** - * Returns promise to trigger a redirect of a popup window window to the end session endpoint. + * Trigger a redirect of a popup window window to the end session endpoint. + * + * @returns A promise */ public async signoutPopup(args: SignoutPopupArgs = {}): Promise { const logger = this._logger.create("signoutPopup"); @@ -519,7 +581,12 @@ export class UserManager { } /** - * Returns promise to process response from the end session endpoint from a popup window. + * Process response (callback) from the end session endpoint from a popup window. + * It is recommend to use {@link UserManager.signoutCallback} instead. + * + * @returns A promise + * + * @see {@link UserManager.signoutCallback} */ public async signoutPopupCallback(url = window.location.href, keepOpen = false): Promise { const logger = this._logger.create("signoutPopupCallback"); @@ -575,7 +642,9 @@ export class UserManager { } /** - * Returns promise to trigger a silent request (via an iframe) to the end session endpoint. + * Trigger a silent request (via an iframe) to the end session endpoint. + * + * @returns A promise */ public async signoutSilent(args: SignoutSilentArgs = {}): Promise { const logger = this._logger.create("signoutSilent"); @@ -601,7 +670,12 @@ export class UserManager { } /** - * Returns promise to notify the parent window of response from the end session endpoint. + * Notify the parent window of response (callback) from the end session endpoint. + * It is recommend to use {@link UserManager.signoutCallback} instead. + * + * @returns A promise + * + * @see {@link UserManager.signoutCallback} */ public async signoutSilentCallback(url = window.location.href): Promise { const logger = this._logger.create("signoutSilentCallback"); diff --git a/src/errors/ErrorResponse.ts b/src/errors/ErrorResponse.ts index cd35ec6c8..76f293afd 100644 --- a/src/errors/ErrorResponse.ts +++ b/src/errors/ErrorResponse.ts @@ -6,9 +6,8 @@ import { Logger } from "../utils"; /** * Error class thrown in case of an authentication error. * - * See https://openid.net/specs/openid-connect-core-1_0.html#AuthError - * * @public + * @see https://openid.net/specs/openid-connect-core-1_0.html#AuthError */ export class ErrorResponse extends Error { /** Marker to detect class: "ErrorResponse" */ diff --git a/src/navigators/IWindow.ts b/src/navigators/IWindow.ts index 5792205c4..e13e275fe 100644 --- a/src/navigators/IWindow.ts +++ b/src/navigators/IWindow.ts @@ -1,5 +1,6 @@ // Copyright (c) Brock Allen & Dominick Baier. All rights reserved. // Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information. + /** * @public */ diff --git a/src/utils/PopupUtils.ts b/src/utils/PopupUtils.ts index e1123ad82..d9a85b54b 100644 --- a/src/utils/PopupUtils.ts +++ b/src/utils/PopupUtils.ts @@ -1,7 +1,7 @@ /** - * @see https://developer.mozilla.org/en-US/docs/Web/API/Window/open#window_features * * @public + * @see https://developer.mozilla.org/en-US/docs/Web/API/Window/open#window_features */ export interface PopupWindowFeatures { left?: number;