Created
March 4, 2021 10:31
-
-
Save MarcelloTheArcane/ce0b3bf2efa2d0b23de3812ab1bf692e 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' | |
const VERSION = '1.0.0' | |
class NhostAuth { | |
constructor (baseUrl) { | |
this._baseUrl = baseUrl | |
this.version = VERSION | |
this._refreshTimeMargin = 45000 | |
this._refreshTimeout = null | |
this._mounted() | |
} | |
async login (email, password) { | |
try { | |
const { data } = await axios.post(`${this._baseUrl}/auth/login`, { | |
email, | |
password, | |
cookie: false, | |
}) | |
this._setRefreshToken(data.refresh_token) | |
this._setJWTToken(data.jwt_token) | |
this._setUser(data.user) | |
this.claims = this._parseJWT(data.jwt_token).payload['https://hasura.io/jwt/claims'] | |
this._triggerRefresh(data.jwt_expires_in - this._refreshTimeMargin) | |
return Promise.resolve(true) | |
} catch (err) { | |
Promise.reject(err.message) | |
} | |
} | |
async register (email, password) { | |
try { | |
await axios.post(`${this._baseUrl}/auth/register`, { | |
email, | |
password, | |
}) | |
Promise.resolve(true) | |
} catch (err) { | |
Promise.reject(err.message) | |
} | |
} | |
requestPasswordReset (email) { | |
return axios.post(`${this._baseUrl}/auth/change-password/request`, { | |
email, | |
}) | |
} | |
resetPassword (ticket, password) { | |
return axios.post(`${this._baseUrl}/auth/change-password/change`, { | |
ticket, | |
password, | |
}) | |
} | |
confirmEmail (ticket) { | |
return axios.get(`${this._baseUrl}/auth/activate?ticket=${ticket}`) | |
} | |
logout () { | |
clearTimeout(this._refreshTimeout) | |
this._refreshTimeout = null | |
this._setRefreshToken(null) | |
this._setJWTToken(null) | |
this._setUser(null) | |
} | |
isAuthenticated () { | |
const authenticated = !!(this._getRefreshToken() && this.getJWTToken() && this._validateJWT(this.getJWTToken())) | |
return authenticated | |
} | |
_parseJWT (JWT) { | |
const splitJWT = JWT.split('.') | |
if (splitJWT.length !== 3) { | |
console.error('Expected 3 parts in JWT, got ' + splitJWT.length) | |
return false | |
} | |
let header = null | |
let payload = null | |
const signature = splitJWT[2] | |
try { | |
header = JSON.parse(atob(splitJWT[0])) | |
payload = JSON.parse(atob(splitJWT[1])) | |
} catch (err) { | |
console.error('Error parsing JWT.') | |
return false | |
} | |
return { | |
header, | |
payload, | |
signature, | |
} | |
} | |
_validateJWT (JWT) { | |
const parsedJWT = this._parseJWT(JWT) | |
return parsedJWT && parsedJWT.header.alg === 'HS256' && Date.now() < (parsedJWT.payload.exp * 1000) | |
} | |
_triggerRefresh (timeout) { | |
this._refreshTimeout = setTimeout(async () => { | |
// Don't bother trying if refresh token is not there | |
if (this._getRefreshToken()) { | |
// Next timeout quickly, unless document is focussed. Then next timeout as per JWT. | |
let nextTimeout = this._refreshTimeMargin + 10000 | |
if (document.hasFocus()) { | |
nextTimeout = await this._loginWithRefresh() | |
} | |
this._triggerRefresh(nextTimeout - this._refreshTimeMargin) | |
} | |
}, timeout) | |
} | |
async _loginWithRefresh () { | |
const { data } = await axios.get(`${this._baseUrl}/auth/token/refresh`, { | |
params: { | |
refresh_token: this._getRefreshToken() | |
} | |
}) | |
this._setRefreshToken(data.refresh_token) | |
this._setJWTToken(data.jwt_token) | |
this._setUser(data.user) | |
return data.jwt_expires_in | |
} | |
_getRefreshToken () { | |
return localStorage.getItem(`tilde_auth_${this.version}_refresh_token`) || null | |
} | |
_setRefreshToken (value) { | |
if (value === null) { | |
localStorage.removeItem(`tilde_auth_${this.version}_refresh_token`) | |
} else { | |
localStorage.setItem(`tilde_auth_${this.version}_refresh_token`, value) | |
} | |
} | |
getJWTToken () { | |
return localStorage.getItem(`tilde_auth_${this.version}_jwt_token`) || null | |
} | |
_setJWTToken (value) { | |
if (value === null) { | |
localStorage.removeItem(`tilde_auth_${this.version}_jwt_token`) | |
} else { | |
localStorage.setItem(`tilde_auth_${this.version}_jwt_token`, value) | |
} | |
} | |
getUser () { | |
return JSON.parse(localStorage.getItem(`tilde_auth_${this.version}_user`)) || {} | |
} | |
_setUser (value) { | |
if (value === null) { | |
localStorage.removeItem(`tilde_auth_${this.version}_user`) | |
} else { | |
localStorage.setItem(`tilde_auth_${this.version}_user`, JSON.stringify(value)) | |
} | |
} | |
_mounted () { | |
if (this.isAuthenticated()) { | |
const parsedJWT = this._parseJWT(this.getJWTToken()) | |
this._triggerRefresh((parsedJWT.payload.exp * 1000) - this._refreshTimeMargin) | |
} else { | |
// Try to log on again | |
this._triggerRefresh(0) | |
} | |
} | |
} | |
class NhostStorage { | |
constructor (baseUrl) { | |
this._baseUrl = baseUrl | |
this.version = VERSION | |
} | |
put (path, file) { | |
const formData = new FormData() | |
formData.append('file', file) | |
if (path.charAt(0) === '/') { | |
path = path.slice(1) | |
} | |
return axios.put(`${this._baseUrl}/storage/o/${path}`, formData, { | |
headers: { | |
'Authorization': `Bearer ${this._getJWTToken()}`, | |
'Content-Type': 'multipart/form-data', | |
} | |
}) | |
} | |
post (path, file) { | |
const formData = new FormData() | |
formData.append('file', file) | |
if (path.charAt(0) === '/') { | |
path = path.slice(1) | |
} | |
return axios.post(`${this._baseUrl}/storage/o/${path}`, formData, { | |
headers: { | |
'Authorization': `Bearer ${this._getJWTToken()}`, | |
'Content-Type': 'multipart/form-data', | |
} | |
}) | |
} | |
delete (path) { | |
if (path.charAt(0) === '/') { | |
path = path.slice(1) | |
} | |
return axios.delete(`${this._baseUrl}/storage/o/${path}`, { | |
headers: { | |
'Authorization': `Bearer ${this._getJWTToken()}`, | |
} | |
}) | |
} | |
get (path) { | |
if (path.charAt(0) === '/') { | |
path = path.slice(1) | |
} | |
return axios.get(`${this._baseUrl}/storage/o/${path}`, { | |
headers: { | |
'Authorization': `Bearer ${this._getJWTToken()}`, | |
} | |
}) | |
} | |
getMetadata (path) { | |
if (path.charAt(0) === '/') { | |
path = path.slice(1) | |
} | |
return axios.get(`${this._baseUrl}/storage/m/${path}`, { | |
headers: { | |
'Authorization': `Bearer ${this._getJWTToken()}`, | |
} | |
}) | |
} | |
_getJWTToken () { | |
return localStorage.getItem(`tilde_auth_${this.version}_jwt_token`) || null | |
} | |
} | |
const auth = new NhostAuth(process.env.VUE_APP_BACKEND_URL) | |
const storage = new NhostStorage(process.env.VUE_APP_BACKEND_URL) | |
export { | |
auth, | |
storage, | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment