import axios from "axios"; import {getUser} from "./user_service"; const current_host = `${window.location.protocol}//${window.location.host}` const oauth_url = `${process.env.REACT_APP_API_SERVER}/oauth`; const client_id = process.env["REACT_APP_CLIENT_ID"]; const generate_challenge = () => { return { code: '5d2309e5bb73b864f989753887fe52f79ce5270395e25862da6940d5', challenge: 'MChCW5vD-3h03HMGFZYskOSTir7II_MMTb8a9rJNhnI', method: 'S256', } } export const redirect_to_code = () => { const challenge = generate_challenge() const params = { response_type: 'code', client_id: client_id, redirect_uri: `${current_host}/login`, scope: 'read write', code_challenge: challenge.challenge, code_challenge_method: challenge.method }; const url = `${oauth_url}/authorize/?${new URLSearchParams(params).toString()}`; window.localStorage.setItem('code_verifier', challenge.code); window.location.href = url; return null; } export const do_auth = async (code, code_verifier) => { const params = { code: code, code_verifier: code_verifier, grant_type: 'authorization_code', redirect_uri: `${current_host}/login`, client_id: client_id, }; const url = `${oauth_url}/token/` const response = await axios.post(url, new URLSearchParams(params)); return response.data } export const do_refresh = async (token) => { const params = { grant_type: 'refresh_token', refresh_token: token, client_id: client_id, }; const url = `${oauth_url}/token/` const response = await axios.post(url, new URLSearchParams(params)); return response.data; } export const auth = async (params) => { // Como response se puede obtener desde refresh o desde un auth regular, se almacena al inicio let response; // Preámbulo, puede existir un refresh_token usable asi que debe hacer el flow de renew if (window.localStorage.getItem('refresh_token')) { const refresh_token = window.localStorage.getItem('refresh_token'); response = await do_refresh(refresh_token); } if (!response) { // Primera fase, obtener código // Si es que no se tiene se tiene que redirigir a la pagina de oauth que entregara el código // a la pagina de redirect como parámetro GET, este trabajo lo hace redirect y se volverá a // ejecutar este método cuando se entre a esa ruta if (!window.localStorage.getItem('code_verifier')) { redirect_to_code(); return {status: 'redirect_to_code'}; } // Segunda fase, se llama a auth con los parámetros de la ruta. // Estos parámetros puede contener un error, en ese caso se elimina el code_verifier del storage // porque no sera util y fallo la request. if (params.error) { window.localStorage.clear() return {status: 'code_error', value: params.error}; } // Teniendo el código en los parámetros se intenta obtener el código de autorización. const code = params.code; const code_verifier = window.localStorage.getItem('code_verifier'); response = await do_auth(code, code_verifier) } // Puede que la respuesta sea errónea por varias razones if (response.error) { return {status: response.error} } // Una vez se tiene la respuesta se almacena el refresh_token y el expires_in // en localstorage para ser utilizado mas tarde para renovar el access_token window.localStorage.clear() const access_token = response.access_token; const refresh = response.refresh_token; const expires = new Date(new Date().getTime() + ((response.expires_in) * 1000)) window.localStorage.setItem('refresh_token', refresh); window.localStorage.setItem('expires', expires); // Almacenar el usuario en localStorage const user = await getUser(access_token); window.localStorage.setItem('user', JSON.stringify(user)) // Finalmente se retorna el access_token para ser utilizado en el estado de la app return {status: 'done', access_token: access_token}; } export const logout = async (access_token) => { // Para hacer logout de un usuario es necesario eliminar el refresh token de su localStorage // y se llama a revocar los tokens en el servidor oauth const revoke_access_params = { token: access_token, client_id: client_id, token_type_hint: 'access_token' } const revoke_refresh_params = { token: window.localStorage.getItem('refresh_token'), client_id: client_id, token_type_hint: 'refresh_token' } window.localStorage.clear(); const url = `${oauth_url}/revoke_token/`; const response_access_revoke = await axios.post(url, new URLSearchParams(revoke_access_params)); const response_refresh_revoke = await axios.post(url, new URLSearchParams(revoke_refresh_params)); return { access_revoke: response_access_revoke, refresh_revoke: response_refresh_revoke, } }