Implémentation du modèle d'authentification "Authorization code with PKCE [1]" [1] https://auth0.com/docs/api-auth/tutorials/authorization-code-grant-pkce
126 lines
3.8 KiB
TypeScript
126 lines
3.8 KiB
TypeScript
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<any> {
|
|
const encoder = new TextEncoder();
|
|
const data = encoder.encode(plain);
|
|
return window.crypto.subtle.digest('SHA-256', data);
|
|
}
|
|
|
|
export function pkceChallengeFromVerifier(v): PromiseLike<string> {
|
|
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<LoginSession> {
|
|
// Based on https://auth0.com/docs/api-auth/tutorials/authorization-code-grant-pkce
|
|
const state = generateRandomString();
|
|
const verifier = generateRandomString();
|
|
|
|
return new Promise<LoginSession>((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');
|
|
} |