@imolinelli/ionic-appauth
Version:
Intergration for OpenId/AppAuth-JS into Ionic V3/4/5
266 lines (265 loc) • 11.9 kB
JavaScript
import { __awaiter } from "tslib";
import { AuthSubject } from "./auth-subject";
import { AuthActionBuilder } from "./auth-action";
import { IonicUserInfoHandler, } from "./user-info-request-handler";
import { IonicEndSessionHandler, } from "./end-session-request-handler";
import { IonicAuthorizationRequestHandler, AUTHORIZATION_RESPONSE_KEY, } from "./authorization-request-handler";
import { DefaultBrowser } from "./auth-browser";
import { BaseTokenRequestHandler, AuthorizationServiceConfiguration, AuthorizationNotifier, TokenResponse, AuthorizationRequest, DefaultCrypto, GRANT_TYPE_AUTHORIZATION_CODE, TokenRequest, GRANT_TYPE_REFRESH_TOKEN, LocalStorageBackend, JQueryRequestor, } from "@openid/appauth";
import { EndSessionRequest, } from "./end-session-request";
import { AuthObserver, ActionHistoryObserver, SessionObserver, } from "./auth-observer";
const TOKEN_RESPONSE_KEY = "token_response";
const AUTH_EXPIRY_BUFFER = 10 * 60 * -1; // 10 mins in seconds
export class AuthService {
constructor(browser = new DefaultBrowser(), storage = new LocalStorageBackend(), requestor = new JQueryRequestor()) {
this.browser = browser;
this.storage = storage;
this.requestor = requestor;
this._authSubject = new AuthSubject();
this._actionHistory = new ActionHistoryObserver();
this._session = new SessionObserver();
this.tokenHandler = new BaseTokenRequestHandler(requestor);
this.userInfoHandler = new IonicUserInfoHandler(requestor);
this.requestHandler = new IonicAuthorizationRequestHandler(browser, storage);
this.endSessionHandler = new IonicEndSessionHandler(browser);
this.setupAuthorizationNotifier();
this.addActionObserver(this._actionHistory);
this.addActionObserver(this._session);
}
get authConfig() {
if (!this._authConfig)
throw new Error("AuthConfig Not Defined");
return this._authConfig;
}
set authConfig(value) {
this._authConfig = value;
}
get configuration() {
if (!this._configuration) {
return AuthorizationServiceConfiguration.fetchFromIssuer(this.authConfig.server_host, this.requestor).catch(() => {
throw new Error("Unable To Obtain Server Configuration");
});
}
if (this._configuration != undefined) {
return Promise.resolve(this._configuration);
}
else {
throw new Error("Unable To Obtain Server Configuration");
}
}
get history() {
return this._actionHistory.history.slice(0);
}
get session() {
return this._session.session;
}
notifyActionListers(action) {
this._authSubject.notify(action);
}
setupAuthorizationNotifier() {
let notifier = new AuthorizationNotifier();
this.requestHandler.setAuthorizationNotifier(notifier);
notifier.setAuthorizationListener((request, response, error) => this.onAuthorizationNotification(request, response, error));
}
onAuthorizationNotification(request, response, error) {
let codeVerifier = request.internal != undefined && this.authConfig.pkce
? request.internal.code_verifier
: undefined;
if (response != null) {
this.requestAccessToken(response.code, codeVerifier);
}
else if (error != null) {
throw new Error(error.errorDescription);
}
else {
throw new Error("Unknown Error With Authentication");
}
}
internalAuthorizationCallback(url) {
return __awaiter(this, void 0, void 0, function* () {
this.browser.closeWindow();
yield this.storage.setItem(AUTHORIZATION_RESPONSE_KEY, url);
return this.requestHandler.completeAuthorizationRequestIfPossible();
});
}
internalEndSessionCallback() {
return __awaiter(this, void 0, void 0, function* () {
this.browser.closeWindow();
yield this.storage.removeItem(TOKEN_RESPONSE_KEY);
this.notifyActionListers(AuthActionBuilder.SignOutSuccess());
});
}
performEndSessionRequest(state) {
return __awaiter(this, void 0, void 0, function* () {
if (this.session.token != undefined) {
let requestJson = {
postLogoutRedirectURI: this.authConfig.end_session_redirect_url,
idTokenHint: this.session.token.idToken || "",
state: state || undefined,
};
let request = new EndSessionRequest(requestJson);
let returnedUrl = yield this.endSessionHandler.performEndSessionRequest(yield this.configuration, request);
//callback may come from showWindow or via another method
if (returnedUrl != undefined) {
this.endSessionCallback();
}
}
else {
//if user has no token they should not be logged in in the first place
this.endSessionCallback();
}
});
}
performAuthorizationRequest(authExtras, state) {
return __awaiter(this, void 0, void 0, function* () {
let requestJson = {
response_type: AuthorizationRequest.RESPONSE_TYPE_CODE,
client_id: this.authConfig.client_id,
redirect_uri: this.authConfig.redirect_url,
scope: this.authConfig.scopes,
extras: authExtras,
state: state || undefined,
};
let request = new AuthorizationRequest(requestJson, new DefaultCrypto(), this.authConfig.pkce);
if (this.authConfig.pkce)
yield request.setupCodeVerifier();
return this.requestHandler.performAuthorizationRequest(yield this.configuration, request);
});
}
requestAccessToken(code, codeVerifier) {
return __awaiter(this, void 0, void 0, function* () {
let requestJSON = {
grant_type: GRANT_TYPE_AUTHORIZATION_CODE,
code: code,
refresh_token: undefined,
redirect_uri: this.authConfig.redirect_url,
client_id: this.authConfig.client_id,
extras: codeVerifier
? {
code_verifier: codeVerifier,
}
: {},
};
let token = yield this.tokenHandler.performTokenRequest(yield this.configuration, new TokenRequest(requestJSON));
yield this.storage.setItem(TOKEN_RESPONSE_KEY, JSON.stringify(token.toJson()));
this.notifyActionListers(AuthActionBuilder.SignInSuccess(token));
});
}
requestTokenRefresh() {
var _a;
return __awaiter(this, void 0, void 0, function* () {
if (!this.session.token) {
throw new Error("No Token Defined!");
}
let requestJSON = {
grant_type: GRANT_TYPE_REFRESH_TOKEN,
refresh_token: (_a = this.session.token) === null || _a === void 0 ? void 0 : _a.refreshToken,
redirect_uri: this.authConfig.redirect_url,
client_id: this.authConfig.client_id,
};
let token = yield this.tokenHandler.performTokenRequest(yield this.configuration, new TokenRequest(requestJSON));
yield this.storage.setItem(TOKEN_RESPONSE_KEY, JSON.stringify(token.toJson()));
this.notifyActionListers(AuthActionBuilder.RefreshSuccess(token));
});
}
internalLoadTokenFromStorage() {
return __awaiter(this, void 0, void 0, function* () {
let token;
let tokenResponseString = yield this.storage.getItem(TOKEN_RESPONSE_KEY);
if (tokenResponseString != null) {
token = new TokenResponse(JSON.parse(tokenResponseString));
if (token) {
return this.notifyActionListers(AuthActionBuilder.LoadTokenFromStorageSuccess(token));
}
}
throw new Error("No Token In Storage");
});
}
internalRequestUserInfo() {
return __awaiter(this, void 0, void 0, function* () {
if (this.session.token) {
let userInfo = yield this.userInfoHandler.performUserInfoRequest(yield this.configuration, this.session.token);
this.notifyActionListers(AuthActionBuilder.LoadUserInfoSuccess(userInfo));
}
else {
throw new Error("No Token Available");
}
});
}
loadTokenFromStorage() {
return __awaiter(this, void 0, void 0, function* () {
yield this.internalLoadTokenFromStorage().catch((response) => {
this.notifyActionListers(AuthActionBuilder.LoadTokenFromStorageFailed(response));
});
});
}
signIn(authExtras, state) {
return __awaiter(this, void 0, void 0, function* () {
yield this.performAuthorizationRequest(authExtras, state).catch((response) => {
this.notifyActionListers(AuthActionBuilder.SignInFailed(response));
});
});
}
signOut(state) {
return __awaiter(this, void 0, void 0, function* () {
yield this.performEndSessionRequest(state).catch((response) => {
this.notifyActionListers(AuthActionBuilder.SignOutFailed(response));
});
});
}
refreshToken() {
return __awaiter(this, void 0, void 0, function* () {
yield this.requestTokenRefresh().catch((response) => {
this.storage.removeItem(TOKEN_RESPONSE_KEY);
this.notifyActionListers(AuthActionBuilder.RefreshFailed(response));
});
});
}
loadUserInfo() {
return __awaiter(this, void 0, void 0, function* () {
yield this.internalRequestUserInfo().catch((response) => {
this.notifyActionListers(AuthActionBuilder.LoadUserInfoFailed(response));
});
});
}
authorizationCallback(callbackUrl) {
this.internalAuthorizationCallback(callbackUrl).catch((response) => {
this.notifyActionListers(AuthActionBuilder.SignInFailed(response));
});
}
endSessionCallback() {
this.internalEndSessionCallback().catch((response) => {
this.notifyActionListers(AuthActionBuilder.SignOutFailed(response));
});
}
getValidToken(buffer = AUTH_EXPIRY_BUFFER) {
return __awaiter(this, void 0, void 0, function* () {
if (this.session.token) {
if (!this.session.token.isValid(buffer)) {
yield this.refreshToken();
if (this.session.token) {
return this.session.token;
}
}
else {
return this.session.token;
}
}
throw new Error("Unable To Obtain Valid Token");
});
}
addActionListener(func) {
let observer = AuthObserver.Create(func);
this.addActionObserver(observer);
return observer;
}
addActionObserver(observer) {
if (this._actionHistory.lastAction) {
observer.update(this._actionHistory.lastAction);
}
this._authSubject.attach(observer);
}
removeActionObserver(observer) {
this._authSubject.detach(observer);
}
}