import { Config } from '../config'; export interface LoginSession { state: string redirectUrl: string verifier: string } export function generateRandomString() { var array = new Uint32Array(28); window.crypto.getRandomValues(array); return Array.from(array, dec => ('0' + dec.toString(16)).substr(-2)).join(''); } export function sha256(plain): PromiseLike { const encoder = new TextEncoder(); const data = encoder.encode(plain); return window.crypto.subtle.digest('SHA-256', data); } export function pkceChallengeFromVerifier(v): PromiseLike { return sha256(v) .then(hashed => base64urlencode(hashed)); } export function base64urlencode(str) { return btoa(String.fromCharCode.apply(null, new Uint8Array(str))) .replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, ''); } export function createLoginSession(): Promise { // Based on https://auth0.com/docs/api-auth/tutorials/authorization-code-grant-pkce const state = generateRandomString(); const verifier = generateRandomString(); return new Promise((resolve, reject) => { try { pkceChallengeFromVerifier(verifier).then(challenge => { console.log('Code challenge is', challenge); let redirectUrl=`${Config.oauth2AuthorizeURL}`; redirectUrl += `?audience=${encodeURIComponent(Config.oauth2Audience)}`; redirectUrl += `&scope=${encodeURIComponent(Config.oauth2Scope)}`; redirectUrl += `&response_type=code`; redirectUrl += `&client_id=${encodeURIComponent(Config.oauth2ClientId)}` redirectUrl += `&code_challenge=${encodeURIComponent(challenge)}`; redirectUrl += `&code_challenge_method=S256` redirectUrl += `&redirect_uri=${encodeURIComponent(Config.oauth2RedirectURI)}`; redirectUrl += `&state=${encodeURIComponent(state)}`; return resolve({ state, redirectUrl, verifier, }); }); } catch(err) { return reject(err); } }); }; export interface AccessTokenRequest { data: FormData, url: string } export function createAccessTokenRequest(code: string, verifier: string): AccessTokenRequest { const data = new FormData(); data.append('grant_type', 'authorization_code'); data.append('client_id', Config.oauth2ClientId); data.append('code_verifier', verifier); data.append('code', code); data.append('redirect_uri', Config.oauth2RedirectURI); return { url: Config.oauth2TokenURL, data, }; }; export function getLogoutURL(rawIdToken: string): string { let logoutURL = Config.oauth2LogoutURL; logoutURL += `?post_logout_redirect_uri=${encodeURIComponent(Config.oauth2PostLogoutRedirectURI)}`; logoutURL += `&id_token_hint=${encodeURIComponent(rawIdToken)}`; return logoutURL; } export interface AccessGrant { access_token: string expires_in: number id_token: string refresh_token: string scope: string token_type: string } export function saveLoginSessionState(verifier: string, state: string) { window.localStorage.setItem('login_verifier', verifier); window.localStorage.setItem('login_state', state); } export function getSavedLoginSessionState(cleanup = true) { const loginSession = { verifier: window.localStorage.getItem('login_verifier'), state: window.localStorage.getItem('login_state') }; if (cleanup) { window.localStorage.removeItem('login_verifier'); window.localStorage.removeItem('login_state'); } return loginSession; } export function saveAccessGrant(grant: AccessGrant) { window.localStorage.setItem('access_grant', JSON.stringify(grant)); } export function getSavedAccessGrant(): AccessGrant { const raw = window.localStorage.getItem('access_grant'); if (raw === "") return null; return JSON.parse(raw) as AccessGrant; } export function clearAccessGrant() { window.localStorage.removeItem('access_grant'); }