Skip to content

Instantly share code, notes, and snippets.

@overthemike
Created August 21, 2018 22:14
Show Gist options
  • Save overthemike/96e4a78f7d448ede69e9061fa9c6efa0 to your computer and use it in GitHub Desktop.
Save overthemike/96e4a78f7d448ede69e9061fa9c6efa0 to your computer and use it in GitHub Desktop.
import { decode } from 'jsonwebtoken'
class AuthService {
constructor(config = {}) {
this.domain = config.domain || '/api'
this.authPath = config.authPath || 'login'
}
login = (username, password) => {
return this.fetch(`${this.domain}/${this.authPath}`, {
method: 'POST',
body: JSON.stringify({
username, password
})
}).then(res => {
this.setToken(res.token)
return Promise.resolve(res)
})
}
logout = () => {
localStorage.removeItem('authtoken')
}
loggedIn = () => {
const token = this.getToken()
return !!token && !this.isTokenExpired(token)
}
isTokenExpired = (token) => {
try {
const decoded = decode(token)
return decoded.exp < Date.now() / 1000
} catch (err) {
return false
}
}
setToken = (token) => {
localStorage.setItem('authtoken', token)
}
getToken = () => {
return localStorage.getItem('authtoken')
}
getProfile = () => {
return decode(this.getToken())
}
get = (url) => {
return this.fetch(url, {
method: 'GET'
})
.then(resp => resp.json())
}
put = (url, data) => {
return this.fetch(url, {
method: 'PUT',
body: JSON.stringify(data)
})
.then(resp => resp.json())
}
post = (url, data) => {
return this.fetch(url, {
method: 'POST',
body: JSON.stringify(data)
})
.then(resp => resp.json())
}
patch = (url, data) => {
return this.fetch(url, {
method: 'PATCH',
body: JSON.stringify(data)
})
.then(resp => resp.json())
}
delete = (url) => {
return this.fetch(url, {
method: 'DELETE'
})
.then(resp => resp.json())
}
fetch = (url, options) => {
const headers = {
'Accept': 'application/json',
'Content-Type': 'application/json'
}
if (this.loggedIn()) {
headers['Authorization'] = 'Bearer ' + this.getToken()
}
return fetch(url, {
headers,
...options
})
.then(this._checkStatus)
.then(response => response.json())
}
_checkStatus = (response) => {
if (response.status >= 200 && response.status < 300) {
return response
} else {
const error = new Error(response.statusText)
error.response = response
throw error
}
}
}
export default AuthService
import React, { Component } from 'react'
import { Route, Redirect } from 'react-router-dom'
import AuthService from '../lib/auth'
export const api = new AuthService()
const AuthContext = React.createContext({
isAuthenticated: false,
redirectUrl: '/login',
defaultRedirect: '/'
})
export class Authentication extends Component {
state = {
isAuthenticated: api.loggedIn()
}
static defaultProps = {
redirectUrl: '/login',
defaultRedirect: '/'
}
signin = (username, password, cb) => {
api.login(username, password)
.then(data => {
this.setState({
isAuthenticated: true
})
cb()
}).catch(err => {
console.log("Error!", err)
})
}
signout = () => {
api.logout()
this.setState({ isAuthenticated: false })
}
render() {
const value = {
isAuthenticated: this.state.isAuthenticated,
redirectUrl: this.props.redirectUrl,
signin: this.signin,
signout: this.signout
}
return (
<AuthContext.Provider value={value}>
{this.props.children}
</AuthContext.Provider>
)
}
}
export const AuthRoute = ({ component: Component, ...rest }) => (
<AuthContext.Consumer>
{ ({ isAuthenticated, redirectUrl }) => (
<Route {...rest} render={(props) => (
isAuthenticated
? <Component {...props} />
: <Redirect to={{
pathname: redirectUrl,
state: { from: props.location }
}}/>
)
}/>
)}
</AuthContext.Consumer>
)
export function withAuth(Component) {
return props => (
<AuthContext.Consumer>
{context => (
<Component {...context} {...props} />
)}
</AuthContext.Consumer>
)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment