Press n or j to go to the next uncovered block, b, p or k for the previous block.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 | /* Copyright (C) Click & Push Accessibility, Inc - All Rights Reserved * Unauthorized copying of this file, via any medium is strictly prohibited * Proprietary and confidential * Written and maintained by the Click & Push Development team * <dev@clicknpush.ca>, January 2022 */ import axios, { AxiosError, AxiosRequestConfig } from "axios"; import { authStore, IdToken } from "./AuthStore"; import { API_URL } from "../../utils/RequestUtils"; import { AuthRequestConfig, DiscoveryDocument, IssuerOrDiscovery, loadAsync, ResponseType } from "expo-auth-session"; import jwt_decode from 'jwt-decode'; export const SECURESTORE_ACCESSTOKEN = "access" export const SECURESTORE_REFRESHTOKEN = "refresh" export const SECURESTORE_NOTIFTOKEN = 'notif' export const SECURESTORE_IDTOKEN = 'id' interface AuthenticationResult { success: boolean errorMessage?: string } /** * Function that initiates the login flow. It opens up with the in app browser and sends an authorization request to the API, which redirects the user to the backend login page. * If the credentials entered are valid, the OAuth Authorization Code flow will occur, which results in the user recieving an access token and refresh token which are then stored in {@link AuthStore}. * */ export const authenticate = async (requestConfig: AuthRequestConfig, discovery: DiscoveryDocument): Promise<AuthenticationResult> => { console.log('[Authentication]: User is attempting to login, opening web portal login...') // initiate authentication request to the server const request = await loadAsync(requestConfig, discovery) // handle authentication response from the server const response = await request.promptAsync(discovery); // if succesful, prepare a request for an access/id token Iif (response.type == "success" && request.codeVerifier) { console.log('[Authentication]: User authentication was successful.') const tokenData = new URLSearchParams(); tokenData.append('grant_type', 'authorization_code'); tokenData.append('client_id', 'atlas.mobile'); tokenData.append('code', response.params.code); tokenData.append('redirect_uri', request.redirectUri); tokenData.append('code_verifier', request.codeVerifier); console.log('[Authentication]: Attempting to retrieve access token...') // send the token request try { const response = await axios.post(API_URL + `/o/token/`, tokenData, { headers: { 'Content-Type': "application/x-www-form-urlencoded" }, }); const tokenResponse = response.data; // if its a successful response, decode the jwt id token, and store the tokens in the corresponding stores const idToken = jwt_decode(tokenResponse.id_token) as IdToken; await authStore.setAccessTokenAsync(tokenResponse.access_token); await authStore.setRefreshTokenAsync(tokenResponse.refresh_token); await authStore.setIdAsync(idToken.sub) console.log('[Authentication]: Tokens successfully retrieved.') return {success: true} } catch (error) { reportAxiosError("Something went wrong when retrieving access token", error); return {success: false, errorMessage: "Something went wrong while logging in. Please try again."} } } } /** * Logs the user out */ export const logout = async () => { try { const tokenParams = new URLSearchParams(); tokenParams.append('client_id', 'atlas.mobile'); tokenParams.append('token', authStore.accessToken as string); const response = await axios.post(API_URL + `/o/revoke-token/`, tokenParams, { headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, }); await authStore.setAccessTokenAsync(null); await authStore.setRefreshTokenAsync(null); await authStore.setNotificationTokenAsync(null); await authStore.setIdAsync(null); } catch (error) { reportAxiosError("Something went wrong when retrieving access token", error); } } /** * If there is a refresh token available, attempts to use it to obtain a new, valid access token. * Used in {@link Atlas} * @memberOf useAuth */ const refreshAccessToken = async () => { Iif (authStore.refreshToken) { try { const tokenData = new URLSearchParams(); tokenData.append('grant_type', 'refresh_token'); tokenData.append('refresh_token', authStore.refreshToken); tokenData.append('client_id', 'atlas.mobile'); console.log('[Authentication]: Attempting to refresh token...') const { data: refreshResponseData } = await axios.post(API_URL + "/o/token/", tokenData, { headers: { 'Content-Type': "application/x-www-form-urlencoded" } }); await authStore.setRefreshTokenAsync(refreshResponseData.refresh_token); await authStore.setAccessTokenAsync(refreshResponseData.access_token); console.info('Successfully refreshed access token, re-attempting initial request...') } catch (error) { reportAxiosError("[Authentication]: Error when trying to refresh access token", error); } } } export const reportAxiosError = (desc: string, error: AxiosError, printResponse?: boolean) => { let errorString = `XHR error: ${desc}\nError code: ${error.response?.status}\nError message: ${error.message}`; Iif (printResponse) { errorString + "\nError response: " + error.response; } console.error(errorString); } |