angular-oauth2-oidc
Version:
Support for OAuth 2(.1) and OpenId Connect (OIDC) in Angular
388 lines (387 loc) • 16 kB
TypeScript
import { NgZone, OnDestroy } from '@angular/core';
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { Observable, Subject, Subscription } from 'rxjs';
import { DateTimeProvider } from './date-time-provider';
import { ValidationHandler, ValidationParams } from './token-validation/validation-handler';
import { UrlHelperService } from './url-helper.service';
import { OAuthEvent, OAuthSuccessEvent } from './events';
import { OAuthLogger, OAuthStorage, LoginOptions, ParsedIdToken, OidcDiscoveryDoc, TokenResponse } from './types';
import { AuthConfig } from './auth.config';
import { HashHandler } from './token-validation/hash-handler';
import * as i0 from "@angular/core";
/**
* Service for logging in and logging out with
* OIDC and OAuth2. Supports implicit flow and
* password flow.
*/
export declare class OAuthService extends AuthConfig implements OnDestroy {
protected ngZone: NgZone;
protected http: HttpClient;
protected config: AuthConfig;
protected urlHelper: UrlHelperService;
protected logger: OAuthLogger;
protected crypto: HashHandler;
protected dateTimeService: DateTimeProvider;
/**
* The ValidationHandler used to validate received
* id_tokens.
*/
tokenValidationHandler: ValidationHandler;
/**
* @internal
* Deprecated: use property events instead
*/
discoveryDocumentLoaded: boolean;
/**
* @internal
* Deprecated: use property events instead
*/
discoveryDocumentLoaded$: Observable<OidcDiscoveryDoc>;
/**
* Informs about events, like token_received or token_expires.
* See the string enum EventType for a full list of event types.
*/
events: Observable<OAuthEvent>;
/**
* The received (passed around) state, when logging
* in with implicit flow.
*/
state?: string;
protected eventsSubject: Subject<OAuthEvent>;
protected discoveryDocumentLoadedSubject: Subject<OidcDiscoveryDoc>;
protected silentRefreshPostMessageEventListener: EventListener;
protected grantTypesSupported: Array<string>;
protected _storage: OAuthStorage;
protected accessTokenTimeoutSubscription: Subscription;
protected idTokenTimeoutSubscription: Subscription;
protected tokenReceivedSubscription: Subscription;
protected automaticRefreshSubscription: Subscription;
protected sessionCheckEventListener: EventListener;
protected jwksUri: string;
protected sessionCheckTimer: any;
protected silentRefreshSubject: string;
protected inImplicitFlow: boolean;
protected saveNoncesInLocalStorage: boolean;
private document;
constructor(ngZone: NgZone, http: HttpClient, storage: OAuthStorage, tokenValidationHandler: ValidationHandler, config: AuthConfig, urlHelper: UrlHelperService, logger: OAuthLogger, crypto: HashHandler, document: Document, dateTimeService: DateTimeProvider);
private checkLocalStorageAccessable;
/**
* Use this method to configure the service
* @param config the configuration
*/
configure(config: AuthConfig): void;
protected configChanged(): void;
restartSessionChecksIfStillLoggedIn(): void;
protected restartRefreshTimerIfStillLoggedIn(): void;
protected setupSessionCheck(): void;
/**
* Will setup up silent refreshing for when the token is
* about to expire. When the user is logged out via this.logOut method, the
* silent refreshing will pause and not refresh the tokens until the user is
* logged back in via receiving a new token.
* @param params Additional parameter to pass
* @param listenTo Setup automatic refresh of a specific token type
*/
setupAutomaticSilentRefresh(params?: object, listenTo?: 'access_token' | 'id_token' | 'any', noPrompt?: boolean): void;
protected refreshInternal(params: any, noPrompt: any): Promise<TokenResponse | OAuthEvent>;
/**
* Convenience method that first calls `loadDiscoveryDocument(...)` and
* directly chains using the `then(...)` part of the promise to call
* the `tryLogin(...)` method.
*
* @param options LoginOptions to pass through to `tryLogin(...)`
*/
loadDiscoveryDocumentAndTryLogin(options?: LoginOptions): Promise<boolean>;
/**
* Convenience method that first calls `loadDiscoveryDocumentAndTryLogin(...)`
* and if then chains to `initLoginFlow()`, but only if there is no valid
* IdToken or no valid AccessToken.
*
* @param options LoginOptions to pass through to `tryLogin(...)`
*/
loadDiscoveryDocumentAndLogin(options?: LoginOptions & {
state?: string;
}): Promise<boolean>;
protected debug(...args: any[]): void;
protected validateUrlFromDiscoveryDocument(url: string): string[];
protected validateUrlForHttps(url: string): boolean;
protected assertUrlNotNullAndCorrectProtocol(url: string | undefined, description: string): void;
protected validateUrlAgainstIssuer(url: string): boolean;
protected setupRefreshTimer(): void;
protected setupExpirationTimers(): void;
protected setupAccessTokenTimer(): void;
protected setupIdTokenTimer(): void;
/**
* Stops timers for automatic refresh.
* To restart it, call setupAutomaticSilentRefresh again.
*/
stopAutomaticRefresh(): void;
protected clearAccessTokenTimer(): void;
protected clearIdTokenTimer(): void;
protected clearAutomaticRefreshTimer(): void;
protected calcTimeout(storedAt: number, expiration: number): number;
/**
* DEPRECATED. Use a provider for OAuthStorage instead:
*
* { provide: OAuthStorage, useFactory: oAuthStorageFactory }
* export function oAuthStorageFactory(): OAuthStorage { return localStorage; }
* Sets a custom storage used to store the received
* tokens on client side. By default, the browser's
* sessionStorage is used.
* @ignore
*
* @param storage
*/
setStorage(storage: OAuthStorage): void;
/**
* Loads the discovery document to configure most
* properties of this service. The url of the discovery
* document is infered from the issuer's url according
* to the OpenId Connect spec. To use another url you
* can pass it to to optional parameter fullUrl.
*
* @param fullUrl
*/
loadDiscoveryDocument(fullUrl?: string): Promise<OAuthSuccessEvent>;
protected loadJwks(): Promise<object>;
protected validateDiscoveryDocument(doc: OidcDiscoveryDoc): boolean;
/**
* Uses password flow to exchange userName and password for an
* access_token. After receiving the access_token, this method
* uses it to query the userinfo endpoint in order to get information
* about the user in question.
*
* When using this, make sure that the property oidc is set to false.
* Otherwise stricter validations take place that make this operation
* fail.
*
* @param userName
* @param password
* @param headers Optional additional http-headers.
*/
fetchTokenUsingPasswordFlowAndLoadUserProfile(userName: string, password: string, headers?: HttpHeaders): Promise<object>;
/**
* Loads the user profile by accessing the user info endpoint defined by OpenId Connect.
*
* When using this with OAuth2 password flow, make sure that the property oidc is set to false.
* Otherwise stricter validations take place that make this operation fail.
*/
loadUserProfile(): Promise<object>;
/**
* Uses password flow to exchange userName and password for an access_token.
* @param userName
* @param password
* @param headers Optional additional http-headers.
*/
fetchTokenUsingPasswordFlow(userName: string, password: string, headers?: HttpHeaders): Promise<TokenResponse>;
/**
* Uses a custom grant type to retrieve tokens.
* @param grantType Grant type.
* @param parameters Parameters to pass.
* @param headers Optional additional HTTP headers.
*/
fetchTokenUsingGrant(grantType: string, parameters: object, headers?: HttpHeaders): Promise<TokenResponse>;
/**
* Refreshes the token using a refresh_token.
* This does not work for implicit flow, b/c
* there is no refresh_token in this flow.
* A solution for this is provided by the
* method silentRefresh.
*/
refreshToken(): Promise<TokenResponse>;
protected removeSilentRefreshEventListener(): void;
protected setupSilentRefreshEventListener(): void;
/**
* Performs a silent refresh for implicit flow.
* Use this method to get new tokens when/before
* the existing tokens expire.
*/
silentRefresh(params?: object, noPrompt?: boolean): Promise<OAuthEvent>;
/**
* This method exists for backwards compatibility.
* {@link OAuthService#initLoginFlowInPopup} handles both code
* and implicit flows.
*/
initImplicitFlowInPopup(options?: {
height?: number;
width?: number;
windowRef?: Window;
}): Promise<unknown>;
initLoginFlowInPopup(options?: {
height?: number;
width?: number;
windowRef?: Window;
}): Promise<unknown>;
protected calculatePopupFeatures(options: {
height?: number;
width?: number;
}): string;
protected processMessageEventMessage(e: MessageEvent): string;
protected canPerformSessionCheck(): boolean;
protected setupSessionCheckEventListener(): void;
protected handleSessionUnchanged(): void;
protected handleSessionChange(): void;
protected waitForSilentRefreshAfterSessionChange(): void;
protected handleSessionError(): void;
protected removeSessionCheckEventListener(): void;
protected initSessionCheck(): void;
protected startSessionCheckTimer(): void;
protected stopSessionCheckTimer(): void;
checkSession(): void;
protected createLoginUrl(state?: string, loginHint?: string, customRedirectUri?: string, noPrompt?: boolean, params?: object): Promise<string>;
initImplicitFlowInternal(additionalState?: string, params?: string | object): void;
/**
* Starts the implicit flow and redirects to user to
* the auth servers' login url.
*
* @param additionalState Optional state that is passed around.
* You'll find this state in the property `state` after `tryLogin` logged in the user.
* @param params Hash with additional parameter. If it is a string, it is used for the
* parameter loginHint (for the sake of compatibility with former versions)
*/
initImplicitFlow(additionalState?: string, params?: string | object): void;
/**
* Reset current implicit flow
*
* @description This method allows resetting the current implict flow in order to be initialized again.
*/
resetImplicitFlow(): void;
protected callOnTokenReceivedIfExists(options: LoginOptions): void;
protected storeAccessTokenResponse(accessToken: string, refreshToken: string, expiresIn: number, grantedScopes: string, customParameters?: Map<string, string>): void;
/**
* Delegates to tryLoginImplicitFlow for the sake of competability
* @param options Optional options.
*/
tryLogin(options?: LoginOptions): Promise<boolean>;
private parseQueryString;
tryLoginCodeFlow(options?: LoginOptions): Promise<void>;
private saveRequestedRoute;
private restoreRequestedRoute;
/**
* Retrieve the returned auth code from the redirect uri that has been called.
* If required also check hash, as we could use hash location strategy.
*/
private getCodePartsFromUrl;
/**
* Get token using an intermediate code. Works for the Authorization Code flow.
*/
private getTokenFromCode;
private fetchAndProcessToken;
/**
* Checks whether there are tokens in the hash fragment
* as a result of the implicit flow. These tokens are
* parsed, validated and used to sign the user in to the
* current client.
*
* @param options Optional options.
*/
tryLoginImplicitFlow(options?: LoginOptions): Promise<boolean>;
private parseState;
protected validateNonce(nonceInState: string): boolean;
protected storeIdToken(idToken: ParsedIdToken): void;
protected storeSessionState(sessionState: string): void;
protected getSessionState(): string;
protected handleLoginError(options: LoginOptions, parts: object): void;
private getClockSkewInMsec;
/**
* @ignore
*/
processIdToken(idToken: string, accessToken: string, skipNonceCheck?: boolean): Promise<ParsedIdToken>;
/**
* Returns the received claims about the user.
*/
getIdentityClaims(): Record<string, any>;
/**
* Returns the granted scopes from the server.
*/
getGrantedScopes(): object;
/**
* Returns the current id_token.
*/
getIdToken(): string;
protected padBase64(base64data: any): string;
/**
* Returns the current access_token.
*/
getAccessToken(): string;
getRefreshToken(): string;
/**
* Returns the expiration date of the access_token
* as milliseconds since 1970.
*/
getAccessTokenExpiration(): number;
protected getAccessTokenStoredAt(): number;
protected getIdTokenStoredAt(): number;
/**
* Returns the expiration date of the id_token
* as milliseconds since 1970.
*/
getIdTokenExpiration(): number;
/**
* Checkes, whether there is a valid access_token.
*/
hasValidAccessToken(): boolean;
/**
* Checks whether there is a valid id_token.
*/
hasValidIdToken(): boolean;
/**
* Retrieve a saved custom property of the TokenReponse object. Only if predefined in authconfig.
*/
getCustomTokenResponseProperty(requestedProperty: string): any;
/**
* Returns the auth-header that can be used
* to transmit the access_token to a service
*/
authorizationHeader(): string;
/**
* Removes all tokens and logs the user out.
* If a logout url is configured, the user is
* redirected to it with optional state parameter.
* @param noRedirectToLogoutUrl
* @param state
*/
logOut(): void;
logOut(customParameters: boolean | object): void;
logOut(noRedirectToLogoutUrl: boolean): void;
logOut(noRedirectToLogoutUrl: boolean, state: string): void;
/**
* @ignore
*/
createAndSaveNonce(): Promise<string>;
/**
* @ignore
*/
ngOnDestroy(): void;
protected createNonce(): Promise<string>;
protected checkAtHash(params: ValidationParams): Promise<boolean>;
protected checkSignature(params: ValidationParams): Promise<any>;
/**
* Start the implicit flow or the code flow,
* depending on your configuration.
*/
initLoginFlow(additionalState?: string, params?: {}): void;
/**
* Starts the authorization code flow and redirects to user to
* the auth servers login url.
*/
initCodeFlow(additionalState?: string, params?: {}): void;
private initCodeFlowInternal;
protected createChallangeVerifierPairForPKCE(): Promise<[
string,
string
]>;
private extractRecognizedCustomParameters;
/**
* Revokes the auth token to secure the vulnarability
* of the token issued allowing the authorization server to clean
* up any security credentials associated with the authorization
*/
revokeTokenAndLogout(customParameters?: boolean | object, ignoreCorsIssues?: boolean): Promise<any>;
/**
* Clear location.hash if it's present
*/
private clearLocationHash;
static ɵfac: i0.ɵɵFactoryDeclaration<OAuthService, [null, null, { optional: true; }, { optional: true; }, { optional: true; }, null, null, { optional: true; }, null, null]>;
static ɵprov: i0.ɵɵInjectableDeclaration<OAuthService>;
}