Created
August 2, 2019 09:04
-
-
Save manuelbieh/81fa5d3cbcc41cfee227af3b146f45bc to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import axios from 'axios'; | |
import applyConverters from 'axios-case-converter'; | |
import { objectKeysToCamelCase } from 'utils'; | |
export const redirectToLogin = () => { | |
window.location.href = process.env.AUTH_URL; | |
}; | |
export const getAccessToken = () => | |
(JSON.parse(window.localStorage.getItem('auth')) || {}).accessToken; | |
export const getRefreshToken = () => | |
(JSON.parse(window.localStorage.getItem('auth')) || {}).refreshToken; | |
// We assume a user is loggedin if he has an AccessToken, no matter if it is valid or not | |
export const isLoggedIn = () => Boolean(getAccessToken()); | |
export const isUnauthorized = (error) => | |
error && error.response && error.response.status === 401; | |
export const storeAuthObject = (authObject) => { | |
window.localStorage.setItem( | |
'auth', | |
JSON.stringify(objectKeysToCamelCase(authObject)) | |
); | |
}; | |
export const getAccessTokenUsingAccessCode = async (accessCode) => { | |
try { | |
const request = axios.create({ baseURL: process.env.API_HOST }); | |
const token = await request.get('/auth/login', { params: { accessCode } }); | |
storeAuthObject(token.data); | |
return true; | |
} catch (err) { | |
return false; | |
} | |
}; | |
export const getAccessTokenUsingRefreshToken = async ( | |
refreshToken = getRefreshToken() | |
) => { | |
try { | |
const request = axios.create({ baseURL: process.env.API_HOST }); | |
const token = await request.get('/auth/refresh', { params: { refreshToken } }); | |
storeAuthObject(token.data); | |
} catch (err) { | |
if (isUnauthorized(err)) { | |
redirectToLogin(); | |
} | |
} | |
}; | |
export const Request = (baseURL = process.env.API_HOST) => { | |
return applyConverters(axios.create({ baseURL })); | |
}; | |
// We're wrapping Axios' http methods here so Axios tries to retrieve a fresh access token using | |
// a possibly existing refresh token first before redirecting to the keycloak login | |
export const wrapAuthenticatedRequestMethod = (client, verb) => ({ | |
[verb]: (...args) => { | |
const makeRequest = async (wasRetried = false) => { | |
try { | |
const response = await client[verb](...args); | |
return response.data; | |
} catch (err) { | |
if (isUnauthorized(err) && wasRetried === false) { | |
await getAccessTokenUsingRefreshToken(); | |
return makeRequest(true); | |
} | |
if (wasRetried === true) { | |
redirectToLogin(); | |
} | |
} | |
}; | |
return makeRequest(); | |
}, | |
}); | |
export const AuthenticatedRequest = (baseURL = process.env.API_HOST) => { | |
const client = Request(baseURL); | |
client.interceptors.request.use((config) => { | |
const accessToken = getAccessToken(); | |
config.headers.common.Authorization = `Bearer ${accessToken || ''}`; | |
return config; | |
}); | |
return { | |
...wrapAuthenticatedRequestMethod(client, 'get'), | |
...wrapAuthenticatedRequestMethod(client, 'post'), | |
...wrapAuthenticatedRequestMethod(client, 'patch'), | |
...wrapAuthenticatedRequestMethod(client, 'put'), | |
...wrapAuthenticatedRequestMethod(client, 'delete'), | |
}; | |
}; | |
export const wrapRequestMethod = (client, verb) => ({ | |
[verb]: async (...args) => { | |
const response = await client[verb](...args); | |
return response.data; | |
}, | |
}); | |
export const wrapRequestMethods = (client, methods = []) => | |
methods.reduce((wrapped, method) => { | |
return { ...wrapped, ...wrapRequestMethod(client, method) }; | |
}, {}); | |
export const API = (client = Request()) => | |
wrapRequestMethods(client, ['get', 'post', 'patch', 'put', 'delete']); | |
export default API; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment