Skip to content
This repository was archived by the owner on Jul 15, 2020. It is now read-only.

Commit 4f37cb1

Browse files
committed
Refactoring to use new next-auth module
The authentication code that was part of this project has not been moved off into seperate modules, to simplify the code base and make it easier to work with. The code is now included in `next-auth` and `next-auth-client` modules on npm. It’s faster, more elegant, contains additional bug fixes and addresses some corner-case bugs. While the `next-auth` project includes it’s own sample implementation, this projects provides a more complete example.
1 parent 9991eb4 commit 4f37cb1

29 files changed

+985
-1456
lines changed

.env.default

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,14 @@
11
SERVER_URL=http://localhost:3000
2-
USER_DB_CONNECTION_STRING=mongodb://localhost:27017/my-database
3-
SESSION_DB_CONNECTION_STRING=mongodb://localhost:27017/my-database
4-
SESSION_SECRET=
5-
LOGS_SECRET=
2+
MONGO_URI=mongodb://localhost:27017/my-database
63
FACEBOOK_ID=
74
FACEBOOK_SECRET=
85
GOOGLE_ID=
96
GOOGLE_SECRET=
107
TWITTER_KEY=
118
TWITTER_SECRET=
12-
EMAIL_ADDRESS=example@gmail.com
9+
EMAIL_ADDRESS=username@gmail.com
1310
EMAIL_SERVER=smtp.gmail.com
1411
EMAIL_PORT=465
1512
EMAIL_SECURE=true
16-
EMAIL_USERNAME=example@gmail.com
13+
EMAIL_USERNAME=username@gmail.com
1714
EMAIL_PASSWORD=

AUTHENTICATION.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ You can pass them on the command line or put them in `.env` file which will be l
88

99
If you want to add new oAuth providers (such as GitHub), you will need to:
1010

11-
* Add the oauth provider configuration in passport.config.js
11+
* Add the oauth provider configuration in next-auth.providers.js
1212
* Add a field to your User model (in 'index.js') with the name of the provider
1313
* Configure the service to point to your website (as in the examples below)
1414
* Specify the environment variables at run time

components/cookies.js

Lines changed: 0 additions & 32 deletions
This file was deleted.

components/layout.js

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@ import { Container, Row, Col, Nav, NavItem, Button, Form, NavLink, Collapse,
66
Navbar, NavbarToggler, NavbarBrand, Modal, ModalHeader, ModalBody,
77
ModalFooter, ListGroup, ListGroupItem } from 'reactstrap'
88
import Signin from './signin'
9-
import Session from '../models/session'
10-
import Cookies from './cookies'
9+
import { NextAuth } from 'next-auth-client'
10+
import Cookies from 'universal-cookie'
1111
import Package from '../package'
1212
import Styles from '../css/index.scss'
1313

@@ -16,6 +16,7 @@ export default class extends React.Component {
1616
static propTypes() {
1717
return {
1818
session: React.PropTypes.object.isRequired,
19+
providers: React.PropTypes.object.isRequired,
1920
children: React.PropTypes.object.isRequired,
2021
fluid: React.PropTypes.boolean
2122
}
@@ -33,8 +34,11 @@ export default class extends React.Component {
3334
toggleModal(e) {
3435
if (e) e.preventDefault()
3536

36-
if (this.state.modal !== true)
37-
Cookies.save('redirect_url', window.location.pathname)
37+
// Save current URL so user is redirected back here after signing in
38+
if (this.state.modal !== true) {
39+
const cookies = new Cookies()
40+
cookies.set('redirect_url', window.location.pathname, { path: '/' })
41+
}
3842

3943
this.setState({
4044
modal: !this.state.modal
@@ -102,7 +106,7 @@ export default class extends React.Component {
102106
<span className="ml-2">&copy; {new Date().getYear() + 1900}.</span>
103107
</p>
104108
</Container>
105-
<SigninModal modal={this.state.modal} toggleModal={this.toggleModal} session={this.props.session}/>
109+
<SigninModal modal={this.state.modal} toggleModal={this.toggleModal} session={this.props.session} providers={this.props.providers}/>
106110
</React.Fragment>
107111
)
108112
}
@@ -164,7 +168,12 @@ export class UserMenu extends React.Component {
164168

165169
async handleSignoutSubmit(event) {
166170
event.preventDefault()
167-
await Session.signout()
171+
172+
// Save current URL so user is redirected back here after signing out
173+
const cookies = new Cookies()
174+
cookies.set('redirect_url', window.location.pathname, { path: '/' })
175+
176+
await NextAuth.signout()
168177
Router.push('/')
169178
}
170179

@@ -209,7 +218,7 @@ export class UserMenu extends React.Component {
209218
* so that users without JavaScript are also redirected to the page
210219
* they were on before they signed in.
211220
**/}
212-
<a href="/auth/signin?redirect=/" className="btn btn-outline-primary" onClick={this.props.toggleModal}><span className="icon ion-md-log-in mr-1"></span> Sign up / Sign in</a>
221+
<a href="/auth?redirect=/" className="btn btn-outline-primary" onClick={this.props.toggleModal}><span className="icon ion-md-log-in mr-1"></span> Sign up / Sign in</a>
213222
</NavItem>
214223
</Nav>
215224
)
@@ -239,7 +248,7 @@ export class SigninModal extends React.Component {
239248
<Modal isOpen={this.props.modal} toggle={this.props.toggleModal} style={{maxWidth: 700}}>
240249
<ModalHeader>Sign up / Sign in</ModalHeader>
241250
<ModalBody style={{padding: '1em 2em'}}>
242-
<Signin session={this.props.session}/>
251+
<Signin session={this.props.session} providers={this.props.providers}/>
243252
</ModalBody>
244253
</Modal>
245254
)

components/page.js

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,30 @@
11
import React from 'react'
22
import Layout from '../components/layout'
3-
import Session from '../models/session'
3+
import { NextAuth } from 'next-auth-client'
44

55
export default class extends React.Component {
66
// Expose session to all pages
77
static async getInitialProps({req}) {
8+
// Export this.props.session to all pages
9+
const session = await NextAuth.init({req})
10+
11+
// If the user is not already signed in, get currently configured providers.
12+
// This project uses them in the sign in dialog, which is embedded on all
13+
// pages when browsing the site but not signed in.
14+
//
15+
// NB: As an improvement, this could alternatively be called on modal load.
16+
const providers = (!session.user) ? await NextAuth.providers({req}) : {}
17+
818
return {
9-
session: await Session.getSession({req}),
10-
lang: 'en'
19+
session: session,
20+
providers: providers,
21+
lang: 'en' // Sets a lang property for accessibility
1122
}
1223
}
1324

1425
adminAcccessOnly() {
1526
return (
16-
<Layout session={this.props.session} navmenu={false}>
27+
<Layout {...this.props} navmenu={false}>
1728
<div className="text-center pt-5 pb-5">
1829
<h1 className="display-4 mb-5">Access Denied</h1>
1930
<p className="lead">You must be signed in as an administrator to access this page.</p>

components/signin.js

Lines changed: 38 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,17 @@
11
import React from 'react'
22
import Router from 'next/router'
33
import { Row, Col, Form, Input, Label, Button } from 'reactstrap'
4-
import Session from '../models/session'
4+
import Cookies from 'universal-cookie'
5+
import { NextAuth } from 'next-auth-client'
56

67
export default class extends React.Component {
8+
79
constructor(props) {
810
super(props)
911
this.state = {
1012
email: '',
11-
session: this.props.session
13+
session: this.props.session,
14+
providers: this.props.providers
1215
}
1316
this.handleSubmit = this.handleSubmit.bind(this)
1417
this.handleEmailChange = this.handleEmailChange.bind(this)
@@ -17,20 +20,25 @@ export default class extends React.Component {
1720

1821
handleEmailChange(event) {
1922
this.setState({
20-
email: event.target.value.trim(),
21-
session: this.state.session
23+
email: event.target.value.trim()
2224
})
2325
}
2426

2527
handleSubmit(event) {
2628
event.preventDefault()
27-
Session.signin(this.state.email)
29+
30+
if (!this.state.email) return
31+
32+
// Save current URL so user is redirected back here after signing in
33+
const cookies = new Cookies()
34+
cookies.set('redirect_url', window.location.pathname, { path: '/' })
35+
36+
NextAuth.signin(this.state.email)
2837
.then(() => {
29-
Router.push('/auth/check-email')
38+
Router.push(`/auth/check-email?email=${this.state.email}`)
3039
})
3140
.catch(err => {
32-
// @FIXME Handle error
33-
console.log(err)
41+
Router.push(`/auth/error?action=signin&type=email&email=${this.state.email}`)
3442
})
3543
}
3644

@@ -40,12 +48,10 @@ export default class extends React.Component {
4048
} else {
4149
return (
4250
<React.Fragment>
43-
<p className="text-center" style={{marginTop: 10, marginBottom: 30}}>If you don't have an account, one will be created when you sign in.</p>
51+
<p className="text-center" style={{marginTop: 10, marginBottom: 30}}>{`If you don't have an account, one will be created when you sign in.`}</p>
4452
<Row>
4553
<Col xs={12} md={6}>
46-
<p><a className="btn btn-outline-dark btn-block btn-facebook" href="/auth/oauth/facebook">Sign in with Facebook</a></p>
47-
<p><a className="btn btn-outline-dark btn-block btn-google" href="/auth/oauth/google">Sign in with Google</a></p>
48-
<p><a className="btn btn-outline-dark btn-block btn-twitter" href="/auth/oauth/twitter">Sign in with Twitter</a></p>
54+
<SignInButtons providers={this.props.providers}/>
4955
</Col>
5056
<Col xs={12} md={6}>
5157
<Form id="signin" method="post" action="/auth/email/signin" onSubmit={this.handleSubmit}>
@@ -64,4 +70,24 @@ export default class extends React.Component {
6470
)
6571
}
6672
}
73+
}
74+
75+
export class SignInButtons extends React.Component {
76+
render() {
77+
return (
78+
<React.Fragment>
79+
{
80+
Object.keys(this.props.providers).map((provider, i) => {
81+
return (
82+
<p key={i}>
83+
<a className="btn btn-block btn-outline-secondary" href={this.props.providers[provider].signin}>
84+
Sign in with {provider}
85+
</a>
86+
</p>
87+
)
88+
})
89+
}
90+
</React.Fragment>
91+
)
92+
}
6793
}

0 commit comments

Comments
 (0)