rsnext/examples/with-cookie-auth/www/utils/auth.js
Juan Olvera 798ae043ac Example with cookie auth (#5821)
Fixes #153

This is my attempt at https://github.com/zeit/next.js/issues/153

Following @rauchg instructions:

- it uses an authentication helper across pages which returns a token if there's one
- it has session synchronization across tabs
- <strike>I deployed a passwordless backend on `now.sh` (https://with-cookie-api.now.sh, [src](https://github.com/j0lv3r4/next.js-with-cookies-api))</strike> The backend is included in the repository and you can deploy everything together by running `now`

Also, from reviewing other PRs, I made sure to:

- use [isomorphic-unfetch](https://www.npmjs.com/package/isomorphic-unfetch).
- use [next-cookies](https://www.npmjs.com/package/next-cookies).

Here's a little demo:

![GIF](https://i.imgur.com/067Ph56.gif)
2018-12-14 23:05:54 +01:00

84 lines
2 KiB
JavaScript

import { Component } from 'react'
import Router from 'next/router'
import nextCookie from 'next-cookies'
import cookie from 'js-cookie'
import fetch from 'isomorphic-unfetch'
export const login = async ({ username, url }) => {
try {
const response = await fetch(url, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ username })
})
if (response.ok) {
const { token } = await response.json()
cookie.set('token', token, { expires: 1 })
Router.push('/profile')
} else {
console.log('Login failed.')
// https://github.com/developit/unfetch#caveats
let error = new Error(response.statusText)
error.response = response
return Promise.reject(error)
}
} catch (error) {
console.error(
'You have an error in your code or there are Network issues.',
error
)
throw new Error(error)
}
}
export const logout = () => {
cookie.remove('token')
// to support logging out from all windows
window.localStorage.setItem('logout', Date.now())
Router.push('/login')
}
export function withAuthSync (WrappedComponent) {
return class extends Component {
constructor (props) {
super(props)
this.syncLogout = this.syncLogout.bind(this)
}
componentDidMount () {
window.addEventListener('storage', this.syncLogout)
}
componentWillUnmount () {
window.removeEventListener('storage', this.syncLogout)
window.localStorage.removeItem('logout')
}
syncLogout (event) {
if (event.key === 'logout') {
console.log('logged out from storage!')
Router.push('/login')
}
}
render () {
return <WrappedComponent {...this.props} />
}
}
}
export default ctx => {
const { token } = nextCookie(ctx)
if (ctx.req && !token) {
ctx.res.writeHead(302, { Location: '/login' })
ctx.res.end()
return
}
if (!token) {
Router.push('/login')
}
return token
}