UNPKG

sk-oidc-oauth

Version:

OIDC/OAuth2 authentication and authorization for prerendered/client-side-rendered SvelteKit apps.

204 lines (203 loc) 7.56 kB
import { derived, writable } from 'svelte/store'; import { Log, Logger, UserManager } from 'oidc-client-ts-lumeris'; export class AuthService { static mgr; static _isLoading = writable(true); static _isAuthenticated = writable(false); static _accessToken = writable(''); static _idToken = writable(''); static _userInfo = writable({}); static _authError = writable(null); static _isExpired = derived(this._userInfo, ($userInfo) => $userInfo?.profile?.exp ? new Date($userInfo.profile.exp * 1000) < new Date() : true); static _isFullyAuthenticated = derived([this._isLoading, this._authError, this._isAuthenticated, this._isExpired], ([$isLoading, $authError, $isAuthenticated, $isExpired]) => !$isLoading && !$authError && $isAuthenticated && !$isExpired); constructor(settings, userManager = UserManager, logger = console, logLevel = Log.ERROR) { Log.setLogger(logger); Log.setLevel(logLevel); AuthService.mgr = userManager ? new userManager(settings) : new UserManager(settings); AuthService.mgr.events.addAccessTokenExpiring(() => { Logger.info('AuthService', 'token expiring'); AuthService.mgr .signinSilent() .then(function (user) { Logger.info('AuthService', 'silent renew success', user); }) .catch(function (e) { Logger.error('AuthService', 'silent renew error', e.message); }); }); AuthService.mgr.events.addAccessTokenExpired(() => { Logger.info('AuthService', 'token expired'); }); AuthService.mgr.events.addSilentRenewError((e) => { Logger.error('AuthService', 'silent renew error', e.message); }); AuthService.mgr.events.addUserLoaded((user) => { AuthService.isAuthenticated.set(true); AuthService.accessToken.set(user.access_token); AuthService.idToken.set(user?.id_token ?? ''); AuthService.userInfo.set({ ...user }); Logger.info('AuthService', 'user loaded', user); }); AuthService.mgr.events.addUserUnloaded(() => { AuthService.isAuthenticated.set(false); AuthService.accessToken.set(''); AuthService.idToken.set(''); AuthService.userInfo.set({}); Logger.info('AuthService', 'user unloaded'); }); AuthService.mgr.events.addUserSignedIn(() => { Logger.info('AuthService', 'user logged in to the token server'); }); AuthService.mgr.events.addUserSignedOut(() => { Logger.info('AuthService', 'user logged out of the token server'); }); } static get isLoading() { return AuthService._isLoading; } static get isAuthenticated() { return AuthService._isAuthenticated; } static get isFullyAuthenticated() { return AuthService._isFullyAuthenticated; } static get isExpired() { return AuthService._isExpired; } static get accessToken() { return AuthService._accessToken; } static get idToken() { return AuthService._idToken; } static get userInfo() { return AuthService._userInfo; } static get authError() { return AuthService._authError; } static async clearLocalStaleState() { try { await AuthService.mgr.clearStaleState(); Logger.info('AuthService', 'clearState success'); } catch (err) { Logger.error('AuthService', 'clearState error', err?.message); } } static async getUser() { try { const user = await AuthService.mgr.getUser(); Logger.info('AuthService', 'got user', user); return user; } catch (err) { Logger.error('AuthService', 'getUser error', err?.message); return null; } } static async removeLocalUser() { try { await AuthService.mgr.removeUser(); Logger.info('AuthService', 'user removed'); } catch (err) { Logger.error('AuthService', 'removeUser error', err?.message); } } static async querySessionStatus() { try { const status = await AuthService.mgr.querySessionStatus(); Logger.info('AuthService', "user's session status", status); } catch (err) { Logger.error('AuthService', 'querySessionStatus error', err?.message); } } static async revokeAccessToken() { try { await AuthService.mgr.revokeTokens(); Logger.info('AuthService', 'access token revoked'); } catch (err) { Logger.info('AuthService', 'revokeAccessToken error', err.message); } } static async startSigninRedirect(redirectTo, additionalState) { try { const addState = additionalState ?? {}; await AuthService.mgr.signinRedirect({ state: { pathname: redirectTo ?? window.location.pathname, search: window.location.search, ...addState, }, }); Logger.info('AuthService', 'signinRedirect done'); } catch (err) { Logger.error('AuthService', 'startSigninMainWindow error', err?.message); } } static async endSigninRedirect() { try { const user = await AuthService.mgr.signinCallback(); // custom state after the login in user.state Logger.info('AuthService', "here's our post-login custom state", user); return user; } catch (err) { Logger.error('AuthService', 'endSigninMainWindow error', err?.message); } } static async popupSignin() { try { const user = await AuthService.mgr.signinPopup(); Logger.info('AuthService', 'signed in', user); } catch (err) { Logger.error('AuthService', 'popupSignin error', err?.message); } } static async popupSignout() { try { await AuthService.mgr.signoutPopup(); Logger.info('AuthService', 'signed out'); } catch (err) { Logger.error('AuthService', 'popupSignout error', err?.message); } } static async silentSignin() { try { const user = await AuthService.mgr.signinSilent(); Logger.info('AuthService', 'signed in silent', user); } catch (err) { Logger.error('AuthService', 'iframeSignin error', err?.message); } } static async startSignoutRedirect() { try { const resp = await AuthService.mgr.signoutRedirect({ state: { pathname: window.location.pathname, search: window.location.search, }, }); Logger.info('AuthService', 'signed out', resp); } catch (err) { Logger.error('AuthService', 'startSignoutMainWindow error', err?.message); } } static async endSignoutRedirect() { try { const resp = await AuthService.mgr.signoutCallback(); Logger.info('AuthService', 'signed out', resp); } catch (err) { Logger.error('AuthService', 'endSignoutMainWindow error', err?.message); } } }