@sneko/ionic-appauth
Version:
Intergration for OpenId/AppAuth-JS into Ionic V3/4/5
413 lines (412 loc) • 19.9 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.AuthService = void 0;
var tslib_1 = require("tslib");
var auth_subject_1 = require("./auth-subject");
var auth_action_1 = require("./auth-action");
var user_info_request_handler_1 = require("./user-info-request-handler");
var end_session_request_handler_1 = require("./end-session-request-handler");
var authorization_request_handler_1 = require("./authorization-request-handler");
var auth_browser_1 = require("./auth-browser");
var appauth_1 = require("@openid/appauth");
var end_session_request_1 = require("./end-session-request");
var auth_observer_1 = require("./auth-observer");
var TOKEN_RESPONSE_KEY = "token_response";
var AUTH_EXPIRY_BUFFER = 10 * 60 * -1; // 10 mins in seconds
var AuthService = /** @class */ (function () {
function AuthService(browser, storage, requestor) {
if (browser === void 0) { browser = new auth_browser_1.DefaultBrowser(); }
if (storage === void 0) { storage = new appauth_1.LocalStorageBackend(); }
if (requestor === void 0) { requestor = new appauth_1.JQueryRequestor(); }
this.browser = browser;
this.storage = storage;
this.requestor = requestor;
this._authSubject = new auth_subject_1.AuthSubject();
this._actionHistory = new auth_observer_1.ActionHistoryObserver();
this._session = new auth_observer_1.SessionObserver();
this.tokenHandler = new appauth_1.BaseTokenRequestHandler(requestor);
this.userInfoHandler = new user_info_request_handler_1.IonicUserInfoHandler(requestor);
this.requestHandler = new authorization_request_handler_1.IonicAuthorizationRequestHandler(browser, storage);
this.endSessionHandler = new end_session_request_handler_1.IonicEndSessionHandler(browser);
this.setupAuthorizationNotifier();
this.addActionObserver(this._actionHistory);
this.addActionObserver(this._session);
}
Object.defineProperty(AuthService.prototype, "authConfig", {
get: function () {
if (!this._authConfig)
throw new Error("AuthConfig Not Defined");
return this._authConfig;
},
set: function (value) {
this._authConfig = value;
},
enumerable: false,
configurable: true
});
Object.defineProperty(AuthService.prototype, "configuration", {
get: function () {
if (!this._configuration) {
return appauth_1.AuthorizationServiceConfiguration.fetchFromIssuer(this.authConfig.server_host, this.requestor)
.catch(function () { 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");
}
},
enumerable: false,
configurable: true
});
Object.defineProperty(AuthService.prototype, "history", {
get: function () {
return this._actionHistory.history.slice(0);
},
enumerable: false,
configurable: true
});
Object.defineProperty(AuthService.prototype, "session", {
get: function () {
return this._session.session;
},
enumerable: false,
configurable: true
});
AuthService.prototype.notifyActionListers = function (action) {
this._authSubject.notify(action);
};
AuthService.prototype.setupAuthorizationNotifier = function () {
var _this = this;
var notifier = new appauth_1.AuthorizationNotifier();
this.requestHandler.setAuthorizationNotifier(notifier);
notifier.setAuthorizationListener(function (request, response, error) { return _this.onAuthorizationNotification(request, response, error); });
};
AuthService.prototype.onAuthorizationNotification = function (request, response, error) {
var 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");
}
};
AuthService.prototype.internalAuthorizationCallback = function (url) {
return tslib_1.__awaiter(this, void 0, void 0, function () {
return tslib_1.__generator(this, function (_a) {
switch (_a.label) {
case 0:
this.browser.closeWindow();
return [4 /*yield*/, this.storage.setItem(authorization_request_handler_1.AUTHORIZATION_RESPONSE_KEY, url)];
case 1:
_a.sent();
return [2 /*return*/, this.requestHandler.completeAuthorizationRequestIfPossible()];
}
});
});
};
AuthService.prototype.internalEndSessionCallback = function () {
return tslib_1.__awaiter(this, void 0, void 0, function () {
return tslib_1.__generator(this, function (_a) {
switch (_a.label) {
case 0:
this.browser.closeWindow();
this._actionHistory.clear();
return [4 /*yield*/, this.storage.removeItem(TOKEN_RESPONSE_KEY)];
case 1:
_a.sent();
this.notifyActionListers(auth_action_1.AuthActionBuilder.SignOutSuccess());
return [2 /*return*/];
}
});
});
};
AuthService.prototype.performEndSessionRequest = function (state) {
return tslib_1.__awaiter(this, void 0, void 0, function () {
var requestJson, request, returnedUrl, _a, _b;
return tslib_1.__generator(this, function (_c) {
switch (_c.label) {
case 0:
if (!(this.session.token != undefined)) return [3 /*break*/, 3];
requestJson = {
postLogoutRedirectURI: this.authConfig.end_session_redirect_url,
idTokenHint: this.session.token.idToken || '',
state: state || undefined,
};
request = new end_session_request_1.EndSessionRequest(requestJson);
_b = (_a = this.endSessionHandler).performEndSessionRequest;
return [4 /*yield*/, this.configuration];
case 1: return [4 /*yield*/, _b.apply(_a, [_c.sent(), request])];
case 2:
returnedUrl = _c.sent();
//callback may come from showWindow or via another method
if (returnedUrl != undefined) {
this.endSessionCallback();
}
return [3 /*break*/, 4];
case 3:
//if user has no token they should not be logged in in the first place
this.endSessionCallback();
_c.label = 4;
case 4: return [2 /*return*/];
}
});
});
};
AuthService.prototype.performAuthorizationRequest = function (authExtras, state) {
return tslib_1.__awaiter(this, void 0, void 0, function () {
var requestJson, request, _a, _b;
return tslib_1.__generator(this, function (_c) {
switch (_c.label) {
case 0:
requestJson = {
response_type: appauth_1.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,
};
request = new appauth_1.AuthorizationRequest(requestJson, new appauth_1.DefaultCrypto(), this.authConfig.pkce);
if (!this.authConfig.pkce) return [3 /*break*/, 2];
return [4 /*yield*/, request.setupCodeVerifier()];
case 1:
_c.sent();
_c.label = 2;
case 2:
_b = (_a = this.requestHandler).performAuthorizationRequest;
return [4 /*yield*/, this.configuration];
case 3: return [2 /*return*/, _b.apply(_a, [_c.sent(), request])];
}
});
});
};
AuthService.prototype.requestAccessToken = function (code, codeVerifier) {
return tslib_1.__awaiter(this, void 0, void 0, function () {
var requestJSON, token, _a, _b;
return tslib_1.__generator(this, function (_c) {
switch (_c.label) {
case 0:
requestJSON = {
grant_type: appauth_1.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
} : {}
};
_b = (_a = this.tokenHandler).performTokenRequest;
return [4 /*yield*/, this.configuration];
case 1: return [4 /*yield*/, _b.apply(_a, [_c.sent(), new appauth_1.TokenRequest(requestJSON)])];
case 2:
token = _c.sent();
return [4 /*yield*/, this.storage.setItem(TOKEN_RESPONSE_KEY, JSON.stringify(token.toJson()))];
case 3:
_c.sent();
this.notifyActionListers(auth_action_1.AuthActionBuilder.SignInSuccess(token));
return [2 /*return*/];
}
});
});
};
AuthService.prototype.requestTokenRefresh = function () {
var _a;
return tslib_1.__awaiter(this, void 0, void 0, function () {
var requestJSON, token, _b, _c;
return tslib_1.__generator(this, function (_d) {
switch (_d.label) {
case 0:
if (!this.session.token) {
throw new Error("No Token Defined!");
}
requestJSON = {
grant_type: appauth_1.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,
};
_c = (_b = this.tokenHandler).performTokenRequest;
return [4 /*yield*/, this.configuration];
case 1: return [4 /*yield*/, _c.apply(_b, [_d.sent(), new appauth_1.TokenRequest(requestJSON)])];
case 2:
token = _d.sent();
return [4 /*yield*/, this.storage.setItem(TOKEN_RESPONSE_KEY, JSON.stringify(token.toJson()))];
case 3:
_d.sent();
this.notifyActionListers(auth_action_1.AuthActionBuilder.RefreshSuccess(token));
return [2 /*return*/];
}
});
});
};
AuthService.prototype.internalLoadTokenFromStorage = function () {
return tslib_1.__awaiter(this, void 0, void 0, function () {
var token, tokenResponseString;
return tslib_1.__generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, this.storage.getItem(TOKEN_RESPONSE_KEY)];
case 1:
tokenResponseString = _a.sent();
if (tokenResponseString != null) {
token = new appauth_1.TokenResponse(JSON.parse(tokenResponseString));
if (token) {
return [2 /*return*/, this.notifyActionListers(auth_action_1.AuthActionBuilder.LoadTokenFromStorageSuccess(token))];
}
}
throw new Error("No Token In Storage");
}
});
});
};
AuthService.prototype.internalRequestUserInfo = function () {
return tslib_1.__awaiter(this, void 0, void 0, function () {
var userInfo, _a, _b;
return tslib_1.__generator(this, function (_c) {
switch (_c.label) {
case 0:
if (!this.session.token) return [3 /*break*/, 3];
_b = (_a = this.userInfoHandler).performUserInfoRequest;
return [4 /*yield*/, this.configuration];
case 1: return [4 /*yield*/, _b.apply(_a, [_c.sent(), this.session.token])];
case 2:
userInfo = _c.sent();
this.notifyActionListers(auth_action_1.AuthActionBuilder.LoadUserInfoSuccess(userInfo));
return [3 /*break*/, 4];
case 3: throw new Error("No Token Available");
case 4: return [2 /*return*/];
}
});
});
};
AuthService.prototype.loadTokenFromStorage = function () {
return tslib_1.__awaiter(this, void 0, void 0, function () {
var _this = this;
return tslib_1.__generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, this.internalLoadTokenFromStorage().catch(function (response) {
_this.notifyActionListers(auth_action_1.AuthActionBuilder.LoadTokenFromStorageFailed(response));
})];
case 1:
_a.sent();
return [2 /*return*/];
}
});
});
};
AuthService.prototype.signIn = function (authExtras, state) {
return tslib_1.__awaiter(this, void 0, void 0, function () {
var _this = this;
return tslib_1.__generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, this.performAuthorizationRequest(authExtras, state).catch(function (response) {
_this.notifyActionListers(auth_action_1.AuthActionBuilder.SignInFailed(response));
})];
case 1:
_a.sent();
return [2 /*return*/];
}
});
});
};
AuthService.prototype.signOut = function (state) {
return tslib_1.__awaiter(this, void 0, void 0, function () {
var _this = this;
return tslib_1.__generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, this.performEndSessionRequest(state).catch(function (response) {
_this.notifyActionListers(auth_action_1.AuthActionBuilder.SignOutFailed(response));
})];
case 1:
_a.sent();
return [2 /*return*/];
}
});
});
};
AuthService.prototype.refreshToken = function () {
return tslib_1.__awaiter(this, void 0, void 0, function () {
var _this = this;
return tslib_1.__generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, this.requestTokenRefresh().catch(function (response) {
_this.storage.removeItem(TOKEN_RESPONSE_KEY);
_this.notifyActionListers(auth_action_1.AuthActionBuilder.RefreshFailed(response));
})];
case 1:
_a.sent();
return [2 /*return*/];
}
});
});
};
AuthService.prototype.loadUserInfo = function () {
return tslib_1.__awaiter(this, void 0, void 0, function () {
var _this = this;
return tslib_1.__generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, this.internalRequestUserInfo().catch(function (response) {
_this.notifyActionListers(auth_action_1.AuthActionBuilder.LoadUserInfoFailed(response));
})];
case 1:
_a.sent();
return [2 /*return*/];
}
});
});
};
AuthService.prototype.authorizationCallback = function (callbackUrl) {
var _this = this;
this.internalAuthorizationCallback(callbackUrl).catch(function (response) {
_this.notifyActionListers(auth_action_1.AuthActionBuilder.SignInFailed(response));
});
};
AuthService.prototype.endSessionCallback = function () {
var _this = this;
this.internalEndSessionCallback().catch(function (response) {
_this.notifyActionListers(auth_action_1.AuthActionBuilder.SignOutFailed(response));
});
};
AuthService.prototype.getValidToken = function (buffer) {
if (buffer === void 0) { buffer = AUTH_EXPIRY_BUFFER; }
return tslib_1.__awaiter(this, void 0, void 0, function () {
return tslib_1.__generator(this, function (_a) {
switch (_a.label) {
case 0:
if (!this.session.token) return [3 /*break*/, 3];
if (!!this.session.token.isValid(buffer)) return [3 /*break*/, 2];
return [4 /*yield*/, this.refreshToken()];
case 1:
_a.sent();
if (this.session.token) {
return [2 /*return*/, this.session.token];
}
return [3 /*break*/, 3];
case 2: return [2 /*return*/, this.session.token];
case 3: throw new Error("Unable To Obtain Valid Token");
}
});
});
};
AuthService.prototype.addActionListener = function (func) {
var observer = auth_observer_1.AuthObserver.Create(func);
this.addActionObserver(observer);
return observer;
};
AuthService.prototype.addActionObserver = function (observer) {
if (this._actionHistory.lastAction) {
observer.update(this._actionHistory.lastAction);
}
this._authSubject.attach(observer);
};
AuthService.prototype.removeActionObserver = function (observer) {
this._authSubject.detach(observer);
};
return AuthService;
}());
exports.AuthService = AuthService;