mirror of
https://github.com/SrIzan10/next-auth.git
synced 2026-05-01 10:55:20 +00:00
Adding support for credentials based sign in
* Resolves #18 by providing an easy way to define a custom credentials based sign in end point and use it with NextAuth. The NextAuth client explicitly supports this option and an new example in example/pages/credentials.js shows how to use it (it’s super easy to use and and you can pass any fields you like to it). Note that this does not explicitly allow a localStrategy to be defined but provides the same ability to define a custom auth hook - allowing custom localStrategies would probably be a footgun and likely generate support requests (as it’s more complicated to implement) so I’m inclined to keep it simple for everyone. * Resolves #20 by passing the req to email sign in method (useful for things like language and hostname detection). * If you do not pass a sendSignInEmail() or signIn() functions (or set them to null) then the routes for these will not be created, so that they are easy to disable.
This commit is contained in:
@@ -18,11 +18,13 @@ When using Server Side Rendering and passed `req` object from **getInitialProps(
|
||||
|
||||
When using Client Side Rendering it will use localStorage (if avalible) to check for cached session data and if not found or expired it call the `/auth/session` end point.
|
||||
|
||||
### NextAuthClient.signin({ email })
|
||||
### NextAuthClient.signin(string or object)
|
||||
|
||||
Client side only method. Request an email sign in token.
|
||||
Client side only method.
|
||||
|
||||
Makes POST request to `/auth/signin`.
|
||||
If passed a string treats it as an email address, generates an email sign in token and makes POST request to `/auth/email/signin`.
|
||||
|
||||
If passed an object treats it as a form to be handled by a custom signIn() function and makes a POST request to `/auth/signin`.
|
||||
|
||||
### NextAuthClient.signout()
|
||||
|
||||
|
||||
16
README.md
16
README.md
@@ -197,15 +197,27 @@ It is where the **next-auth.functions.js** and **next-auth.providers.js** files
|
||||
|
||||
Methods for user management and sending email are defined in **next-auth.functions.js**
|
||||
|
||||
The example configuration provided is for Mongo DB. By defining the behaviour in these functions you can use NextAuth with any database, including a relational database that uses SQL.
|
||||
|
||||
#### Required
|
||||
|
||||
* find({id,email,emailToken,provider})
|
||||
* insert(user, oAuthProfile)
|
||||
* update(user, oAuthProfile)
|
||||
* remove(id)
|
||||
* serialize(user)
|
||||
* deserialize(id)
|
||||
* sendSigninEmail({email, url})
|
||||
|
||||
The example configuration provided is for Mongo DB. By defining the behaviour in these functions you can use NextAuth with any database, including a relational database that uses SQL.
|
||||
#### Optional
|
||||
|
||||
* sendSigninEmail({email, url, req})
|
||||
* signIn({form, req})
|
||||
|
||||
The `sendSigninEmail()` method is used to send an email for email token based sign in (one time use passwords). Omit it or set it to null to disable email based sign in.
|
||||
|
||||
The `signIn()` method is used to handle authenticating with custom credentials (e.g. username and password, 2FA token, etc). Omit it or leave it undefined unless you need it.
|
||||
|
||||
You can use any combination of authentication methods (email, credentials, oAuth providers).
|
||||
|
||||
### next-auth.providers.js
|
||||
|
||||
|
||||
@@ -33,6 +33,8 @@ This example includes the following pages:
|
||||
* pages/auth/check-email.js
|
||||
* pages/auth/callback.js
|
||||
|
||||
The file `pages/auth/credentials.js` provides an additional example of how to use a custom authentication handler defined in `next-auth.functions.js`.
|
||||
|
||||
## Configuration
|
||||
|
||||
It also includes the following configuration files:
|
||||
|
||||
@@ -57,16 +57,16 @@ const nodemailerDirectTransport = require('nodemailer-direct-transport')
|
||||
let nodemailerTransport = nodemailerDirectTransport()
|
||||
if (process.env.EMAIL_SERVER && process.env.EMAIL_USERNAME && process.env.EMAIL_PASSWORD) {
|
||||
nodemailerTransport = nodemailerSmtpTransport({
|
||||
host: process.env.EMAIL_SERVER,
|
||||
port: process.env.EMAIL_PORT || 25,
|
||||
secure: true,
|
||||
auth: {
|
||||
user: process.env.EMAIL_USERNAME,
|
||||
pass: process.env.EMAIL_PASSWORD
|
||||
}
|
||||
})
|
||||
host: process.env.EMAIL_SERVER,
|
||||
port: process.env.EMAIL_PORT || 25,
|
||||
secure: true,
|
||||
auth: {
|
||||
user: process.env.EMAIL_USERNAME,
|
||||
pass: process.env.EMAIL_PASSWORD
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
module.exports = () => {
|
||||
return new Promise((resolve, reject) => {
|
||||
if (process.env.MONGO_URI) {
|
||||
@@ -166,8 +166,8 @@ module.exports = () => {
|
||||
// Handle responses from deserialize()
|
||||
return Promise.resolve(user.id)
|
||||
} else if (user._id) {
|
||||
// Handle responses from find(), insert(), update()
|
||||
return Promise.resolve(user._id)
|
||||
// Handle responses from find(), insert(), update()
|
||||
return Promise.resolve(user._id)
|
||||
} else {
|
||||
return Promise.reject(new Error("Unable to serialise user"))
|
||||
}
|
||||
@@ -193,11 +193,14 @@ module.exports = () => {
|
||||
})
|
||||
})
|
||||
},
|
||||
// Define method for sending links for signing in over email.
|
||||
sendSignInEmail: ({
|
||||
email = null,
|
||||
url = null
|
||||
} = {}) => {
|
||||
// Email Sign In
|
||||
//
|
||||
// Accounts are created automatically, as when signing in via oAuth.
|
||||
// Users are sent one-time use sign in tokens in links. This avoids
|
||||
// storing user supplied passwords anywhere, preventing password re-use.
|
||||
//
|
||||
// To disable this option, do not set sendSignInEmail (or set it to null).
|
||||
sendSignInEmail: ({email, url, req}) => {
|
||||
nodemailer
|
||||
.createTransport(nodemailerTransport)
|
||||
.sendMail({
|
||||
@@ -213,8 +216,40 @@ module.exports = () => {
|
||||
})
|
||||
if (process.env.NODE_ENV === 'development') {
|
||||
console.log('Generated sign in link ' + url + ' for ' + email)
|
||||
}
|
||||
}
|
||||
},
|
||||
// Credentials Sign In
|
||||
//
|
||||
// If you use this you will need to define your own way to validate
|
||||
// credentials. Unlike with oAuth or Email Sign In, accounts are not
|
||||
// created automatically so you will need to provide a way to create them.
|
||||
//
|
||||
// This feature is intended for strategies like Two Factor Authentication.
|
||||
//
|
||||
// To disable this option, do not set signin (or set it to null).
|
||||
/*
|
||||
signIn: ({form, req}) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
// Should validate credentials (e.g. hash password, compare 2FA token
|
||||
// etc) and return a valid user object from a database.
|
||||
return usersCollection.findOne({
|
||||
email: form.email
|
||||
}, (err, user) => {
|
||||
if (err) return reject(err)
|
||||
if (!user) return resolve(null)
|
||||
|
||||
// Check credentials - e.g. compare bcrypt password hashes
|
||||
if (form.password == "test1234") {
|
||||
// If valid, return user object - e.g. { id, name, email }
|
||||
return resolve(user)
|
||||
} else {
|
||||
// If invalid, return null
|
||||
return resolve(null)
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
*/
|
||||
})
|
||||
})
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "next-auth-examples",
|
||||
"version": "1.7.3",
|
||||
"version": "1.8.0",
|
||||
"description": "An example project for next-auth",
|
||||
"repository": "https://github.com/iaincollins/next-auth.git",
|
||||
"main": "",
|
||||
@@ -18,7 +18,7 @@
|
||||
"mongodb": "^3.0.1",
|
||||
"nedb": "^1.8.0",
|
||||
"next": "^5.0.0",
|
||||
"next-auth": "^1.7.3",
|
||||
"next-auth": "^1.8.0",
|
||||
"nodemailer": "^4.4.2",
|
||||
"nodemailer-direct-transport": "^3.3.2",
|
||||
"nodemailer-smtp-transport": "^2.7.4",
|
||||
|
||||
117
example/pages/auth/credentials.js
Normal file
117
example/pages/auth/credentials.js
Normal file
@@ -0,0 +1,117 @@
|
||||
import React from 'react'
|
||||
import Head from 'next/head'
|
||||
import Router from 'next/router'
|
||||
import Link from 'next/link'
|
||||
import { NextAuth } from 'next-auth/client'
|
||||
|
||||
export default class extends React.Component {
|
||||
|
||||
static async getInitialProps({req}) {
|
||||
return {
|
||||
session: await NextAuth.init({req}),
|
||||
linkedAccounts: await NextAuth.linked({req}),
|
||||
providers: await NextAuth.providers({req})
|
||||
}
|
||||
}
|
||||
|
||||
constructor(props) {
|
||||
super(props)
|
||||
this.state = {
|
||||
email: '',
|
||||
password: '',
|
||||
session: this.props.session
|
||||
}
|
||||
this.handleEmailChange = this.handleEmailChange.bind(this)
|
||||
this.handlePasswordChange = this.handlePasswordChange.bind(this)
|
||||
this.handleSignInSubmit = this.handleSignInSubmit.bind(this)
|
||||
}
|
||||
|
||||
async componentDidMount() {
|
||||
if (this.props.session.user) {
|
||||
Router.push(`/auth/`)
|
||||
}
|
||||
}
|
||||
|
||||
handleEmailChange(event) {
|
||||
this.setState({
|
||||
email: event.target.value
|
||||
})
|
||||
}
|
||||
|
||||
handlePasswordChange(event) {
|
||||
this.setState({
|
||||
password: event.target.value
|
||||
})
|
||||
}
|
||||
|
||||
handleSignInSubmit(event) {
|
||||
event.preventDefault()
|
||||
|
||||
// An object passed NextAuth.signin will be passed to your signin() function
|
||||
NextAuth.signin({
|
||||
email: this.state.email,
|
||||
password: this.state.password
|
||||
})
|
||||
.then(authenticated => {
|
||||
Router.push(`/auth/callback`)
|
||||
})
|
||||
.catch(() => {
|
||||
alert("Authentication failed.")
|
||||
})
|
||||
}
|
||||
|
||||
render() {
|
||||
if (this.props.session.user) {
|
||||
return null
|
||||
} else {
|
||||
return (
|
||||
<div className="container">
|
||||
<Head>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1"/>
|
||||
<script src="https://cdn.polyfill.io/v2/polyfill.min.js"/>
|
||||
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossOrigin="anonymous"/>
|
||||
</Head>
|
||||
<div className="text-center">
|
||||
<h1 className="display-4 mt-3 mb-3">NextAuth Example</h1>
|
||||
</div>
|
||||
<div className="row">
|
||||
<div className="col-sm-6 mr-auto ml-auto">
|
||||
<p>
|
||||
If you need password based sign in, two factor authentication
|
||||
or some other credentials based sign in method, you can define
|
||||
a signin() function in <strong>next-auth.functions.js</strong>.
|
||||
You can pass in any properties you need (e.g. username and password,
|
||||
a token, etc) to NextAuth.signin().
|
||||
</p>
|
||||
<div className="card mt-3 mb-3">
|
||||
<h4 className="card-header">Sign In</h4>
|
||||
<div className="card-body pb-0">
|
||||
<p className="text-italic text-muted text-center">
|
||||
Tip: Create an account first then try the password "test1234".
|
||||
</p>
|
||||
<form id="signin" method="post" action="/auth/signin" onSubmit={this.handleSignInSubmit}>
|
||||
<input name="_csrf" type="hidden" value={this.state.session.csrfToken}/>
|
||||
<p>
|
||||
<label htmlFor="email">Email address</label><br/>
|
||||
<input name="email" type="text" placeholder="j.smith@example.com" id="email" className="form-control" value={this.state.email} onChange={this.handleEmailChange}/>
|
||||
</p>
|
||||
<p>
|
||||
<label htmlFor="password">Password</label><br/>
|
||||
<input name="password" type="password" placeholder="" id="email" className="form-control" value={this.state.password} onChange={this.handlePasswordChange}/>
|
||||
</p>
|
||||
<p className="text-right">
|
||||
<button id="submitButton" type="submit" className="btn btn-outline-primary">Sign in</button>
|
||||
</p>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<p className="text-center">
|
||||
<Link href="/auth"><a>Back</a></Link>
|
||||
</p>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -39,7 +39,7 @@ export default class extends React.Component {
|
||||
.then(() => {
|
||||
Router.push(`/auth/check-email?email=${this.state.email}`)
|
||||
})
|
||||
.catch(err => {
|
||||
.catch(() => {
|
||||
Router.push(`/auth/error?action=signin&type=email&email=${this.state.email}`)
|
||||
})
|
||||
}
|
||||
@@ -55,7 +55,7 @@ export default class extends React.Component {
|
||||
</Head>
|
||||
<div className="text-center">
|
||||
<h1 className="display-4 mt-3">NextAuth Example</h1>
|
||||
<p className="lead mt-3 mb-1">You are signed in as <span className="font-weight-bold">{this.props.session.user.name || this.props.session.user.email}</span>.</p>
|
||||
<p className="lead mt-3 mb-1">You are signed in as <span className="font-weight-bold">{this.props.session.user.email}</span>.</p>
|
||||
</div>
|
||||
<div className="row">
|
||||
<div className="col-sm-5 mr-auto ml-auto">
|
||||
@@ -101,6 +101,9 @@ export default class extends React.Component {
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<p className="text-center small">
|
||||
<Link href="/auth/credentials"><a>Sign in with credentials</a></Link>
|
||||
</p>
|
||||
<p className="text-center">
|
||||
<Link href="/"><a>Home</a></Link>
|
||||
</p>
|
||||
|
||||
201
index.js
201
index.js
@@ -63,11 +63,17 @@ module.exports = (nextApp, {
|
||||
remove: (id) => { Promise.resolve(id) },
|
||||
serialize: (user) => { Promise.resolve(id) },
|
||||
deserialize: (id) => { Promise.resolve(user) },
|
||||
sendSignInEmail: ({
|
||||
sendSignInEmail: null, /* ({
|
||||
email = null,
|
||||
url = null,
|
||||
req = null
|
||||
} = {}) => { Promise.resolve(true) }
|
||||
*/
|
||||
signIn: null /* ({
|
||||
email = null,
|
||||
password = null
|
||||
} = {}) => { Promise.resolve(user) }
|
||||
*/
|
||||
}
|
||||
} = {}) => {
|
||||
|
||||
@@ -88,7 +94,7 @@ module.exports = (nextApp, {
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* Set up body parsing, express sessions and add CSRF tokens.
|
||||
*
|
||||
* You can set bodyParser to false and pass an Express instance if you want
|
||||
@@ -119,7 +125,7 @@ module.exports = (nextApp, {
|
||||
expressApp.set('trust proxy', 1)
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* With sessions configured we need to configure Passport and trigger
|
||||
* passport.initialize() before we add any other routes.
|
||||
*/
|
||||
@@ -130,7 +136,7 @@ module.exports = (nextApp, {
|
||||
functions: functions
|
||||
})
|
||||
|
||||
/**
|
||||
/*
|
||||
* Add route to get CSRF token via AJAX
|
||||
*/
|
||||
expressApp.get(`${pathPrefix}/csrf`, (req, res) => {
|
||||
@@ -139,7 +145,7 @@ module.exports = (nextApp, {
|
||||
})
|
||||
})
|
||||
|
||||
/**
|
||||
/*
|
||||
* Return session info
|
||||
*/
|
||||
expressApp.get(`${pathPrefix}/session`, (req, res) => {
|
||||
@@ -162,7 +168,7 @@ module.exports = (nextApp, {
|
||||
return res.json(session)
|
||||
})
|
||||
|
||||
/**
|
||||
/*
|
||||
* Return list of which accounts are already linked.
|
||||
*
|
||||
* We define this both as a server side function and a RESTful endpoint so
|
||||
@@ -222,7 +228,7 @@ module.exports = (nextApp, {
|
||||
})
|
||||
})
|
||||
|
||||
/**
|
||||
/*
|
||||
* Return list of configured oAuth Providers
|
||||
*
|
||||
* We define this both as a server side function and a RESTful endpoint so
|
||||
@@ -257,80 +263,133 @@ module.exports = (nextApp, {
|
||||
return res.json(configuredProviders)
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
/*
|
||||
* Enable /auth/signin routes if signIn() function is passed
|
||||
*/
|
||||
if (functions.signIn) {
|
||||
expressApp.post(`${pathPrefix}/signin`, (req, res) => {
|
||||
// Passes all supplied credentials to the signIn function
|
||||
functions.signIn({
|
||||
form: req.body,
|
||||
req: req
|
||||
})
|
||||
.then(user => {
|
||||
if (user) {
|
||||
// If signIn() returns a user, sign in as them
|
||||
req.logIn(user, (err) => {
|
||||
if (err) return res.redirect(`${pathPrefix}/error?action=signin&type=credentials`)
|
||||
if (req.xhr) {
|
||||
// If AJAX request (from client with JS), return JSON response
|
||||
return res.json({success: true})
|
||||
} else {
|
||||
// If normal form POST (from client without JS) return redirect
|
||||
return res.redirect(`${pathPrefix}/callback?action=signin&service=credentials`)
|
||||
}
|
||||
})
|
||||
} else {
|
||||
// If no user object is returned, bounce back to the sign in page
|
||||
return res.redirect(`${pathPrefix}`)
|
||||
}
|
||||
})
|
||||
.catch(err => {
|
||||
return res.redirect(`${pathPrefix}/error?action=signin&type=credentials`)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a one time use sign in link and email it to the user
|
||||
/*
|
||||
* Enable /auth/email/signin routes if sendSignInEmail() function is passed
|
||||
*/
|
||||
expressApp.post(`${pathPrefix}/email/signin`, (req, res) => {
|
||||
const email = req.body.email || null
|
||||
if (functions.sendSignInEmail) {
|
||||
/*
|
||||
* Generate a one time use sign in link and email it to the user
|
||||
*/
|
||||
expressApp.post(`${pathPrefix}/email/signin`, (req, res) => {
|
||||
const email = req.body.email || null
|
||||
|
||||
if (!email || email.trim() === '') {
|
||||
res.redirect(`${pathPrefix}`)
|
||||
}
|
||||
if (!email || email.trim() === '') {
|
||||
res.redirect(`${pathPrefix}`)
|
||||
}
|
||||
|
||||
const token = uuid()
|
||||
const url = (serverUrl || `${req.protocol}://${req.headers.host}`) + `${pathPrefix}/email/signin/${token}`
|
||||
const token = uuid()
|
||||
const url = (serverUrl || `${req.protocol}://${req.headers.host}`) + `${pathPrefix}/email/signin/${token}`
|
||||
|
||||
// Create verification token save it to database
|
||||
functions.find({ email: email })
|
||||
.then(user => {
|
||||
if (user) {
|
||||
// If a user with that email address exists already, update token.
|
||||
user.emailToken = token
|
||||
return functions.update(user)
|
||||
} else {
|
||||
// If the user does not exist, create a new account with the token.
|
||||
return functions.insert({
|
||||
email: email,
|
||||
emailToken: token
|
||||
// Create verification token save it to database
|
||||
functions.find({ email: email })
|
||||
.then(user => {
|
||||
if (user) {
|
||||
// If a user with that email address exists already, update token.
|
||||
user.emailToken = token
|
||||
return functions.update(user)
|
||||
} else {
|
||||
// If the user does not exist, create a new account with the token.
|
||||
return functions.insert({
|
||||
email: email,
|
||||
emailToken: token
|
||||
})
|
||||
}
|
||||
})
|
||||
.then(user => {
|
||||
functions.sendSignInEmail({
|
||||
email: user.email,
|
||||
url: url,
|
||||
req: req
|
||||
})
|
||||
}
|
||||
})
|
||||
.then(user => {
|
||||
functions.sendSignInEmail({
|
||||
email: user.email,
|
||||
url: url
|
||||
if (req.xhr) {
|
||||
// If AJAX request (from client with JS), return JSON response
|
||||
return res.json({success: true})
|
||||
} else {
|
||||
// If normal form POST (from client without JS) return redirect
|
||||
return res.redirect(`${pathPrefix}/check-email?email=${email}`)
|
||||
}
|
||||
})
|
||||
return res.redirect(`${pathPrefix}/check-email?email=${email}`)
|
||||
})
|
||||
.catch(err => {
|
||||
return res.redirect(`${pathPrefix}/error?action=signin&type=email&email=${email}`)
|
||||
})
|
||||
})
|
||||
|
||||
/**
|
||||
* Verify token in callback URL for email sign in
|
||||
*/
|
||||
expressApp.get(`${pathPrefix}/email/signin/:token`, (req, res) => {
|
||||
if (!req.params.token) {
|
||||
return res.redirect(`${pathPrefix}/error?action=signin&type=token-missing`)
|
||||
}
|
||||
|
||||
functions.find({ emailToken: req.params.token })
|
||||
.then(user => {
|
||||
if (user) {
|
||||
// Delete current token so it cannot be used again
|
||||
delete user.emailToken
|
||||
// Mark email as verified now we know they have access to it
|
||||
user.emailVerified = true
|
||||
return functions.update(user)
|
||||
} else {
|
||||
return Promise.reject(new Error("Token not valid"))
|
||||
}
|
||||
})
|
||||
.then(user => {
|
||||
// If the user object is valid, sign the user in
|
||||
req.logIn(user, (err) => {
|
||||
if (err) throw err
|
||||
return res.redirect(`${pathPrefix}/callback?action=signin&service=email`)
|
||||
.catch(err => {
|
||||
return res.redirect(`${pathPrefix}/error?action=signin&type=email&email=${email}`)
|
||||
})
|
||||
})
|
||||
.catch(err => {
|
||||
return res.redirect(`${pathPrefix}/error?action=signin&type=token-invalid`)
|
||||
})
|
||||
})
|
||||
|
||||
/**
|
||||
/*
|
||||
* Verify token in callback URL for email sign in
|
||||
*/
|
||||
expressApp.get(`${pathPrefix}/email/signin/:token`, (req, res) => {
|
||||
if (!req.params.token) {
|
||||
return res.redirect(`${pathPrefix}/error?action=signin&type=token-missing`)
|
||||
}
|
||||
|
||||
functions.find({ emailToken: req.params.token })
|
||||
.then(user => {
|
||||
if (user) {
|
||||
// Delete current token so it cannot be used again
|
||||
delete user.emailToken
|
||||
// Mark email as verified now we know they have access to it
|
||||
user.emailVerified = true
|
||||
return functions.update(user)
|
||||
} else {
|
||||
return Promise.reject(new Error("Token not valid"))
|
||||
}
|
||||
})
|
||||
.then(user => {
|
||||
// If the user object is valid, sign the user in
|
||||
req.logIn(user, (err) => {
|
||||
if (err) return res.redirect(`${pathPrefix}/error?action=signin&type=token-invalid`)
|
||||
if (req.xhr) {
|
||||
// If AJAX request (from client with JS), return JSON response
|
||||
return res.json({success: true})
|
||||
} else {
|
||||
// If normal form POST (from client without JS) return redirect
|
||||
return res.redirect(`${pathPrefix}/callback?action=signin&service=email`)
|
||||
}
|
||||
})
|
||||
})
|
||||
.catch(err => {
|
||||
return res.redirect(`${pathPrefix}/error?action=signin&type=token-invalid`)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
/*
|
||||
* Sign a user out
|
||||
*/
|
||||
expressApp.post(`${pathPrefix}/signout`, (req, res) => {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "next-auth",
|
||||
"version": "1.7.3",
|
||||
"version": "1.8.0",
|
||||
"description": "An authentication library for Next.js",
|
||||
"repository": "https://github.com/iaincollins/next-auth.git",
|
||||
"main": "index.js",
|
||||
|
||||
@@ -151,43 +151,57 @@ export default class {
|
||||
.then(data => data)
|
||||
.catch(() => Error('Unable to get oAuth providers'))
|
||||
}
|
||||
|
||||
static async signin(email) {
|
||||
// Sign in to the server
|
||||
|
||||
// Load current session info from cache
|
||||
let session = await this.init()
|
||||
|
||||
// Make sure we have the latest CSRF Token in our session
|
||||
session.csrfToken = await this.csrfToken()
|
||||
/*
|
||||
* Sign in
|
||||
*
|
||||
* Will post a form to /auth/signin auth route if an object is passed.
|
||||
* If the details are valid a session will be created and you should redirect
|
||||
* to your callback page so the session is loaded in the client.
|
||||
*
|
||||
* If just a string containing an email address is specififed will generate a
|
||||
* a one-time use sign in link and send it via email; you should redirect to a
|
||||
* page telling the user to check their inbox for an email with the link.
|
||||
*/
|
||||
static async signin(params) {
|
||||
// Params can be just string (an email address) or an object (form fields)
|
||||
const formData = (typeof params === 'string') ? { email: params } : params
|
||||
|
||||
const formData = {
|
||||
_csrf: session.csrfToken,
|
||||
email,
|
||||
}
|
||||
// Use either the email token generation route or the custom form auth route
|
||||
const route = (typeof params === 'string') ? '/auth/email/signin' : '/auth/signin'
|
||||
|
||||
// Add latest CSRF Token to request
|
||||
formData._csrf = await this.csrfToken()
|
||||
|
||||
// Encoded form parser for sending data in the body
|
||||
const encodedForm = Object.keys(formData).map((key) => {
|
||||
return encodeURIComponent(key) + '=' + encodeURIComponent(formData[key])
|
||||
}).join('&')
|
||||
|
||||
return fetch('/auth/email/signin', {
|
||||
return fetch(route, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/x-www-form-urlencoded'
|
||||
'Content-Type': 'application/x-www-form-urlencoded',
|
||||
'X-Requested-With': 'XMLHttpRequest' // So Express can detect AJAX post
|
||||
},
|
||||
body: encodedForm,
|
||||
credentials: 'same-origin'
|
||||
})
|
||||
.then(response => {
|
||||
.then(async response => {
|
||||
if (response.ok) {
|
||||
return response
|
||||
return await response.json()
|
||||
} else {
|
||||
return Promise.reject(Error('HTTP error while attempting to sign in'))
|
||||
throw new Error('HTTP error while attempting to sign in')
|
||||
}
|
||||
})
|
||||
.then(data => {
|
||||
if (data.success && data.success === true) {
|
||||
return Promise.resolve(true)
|
||||
} else {
|
||||
return Promise.resolve(false)
|
||||
}
|
||||
})
|
||||
.then(() => true)
|
||||
.catch(() => Error('Unable to sign in'))
|
||||
}
|
||||
|
||||
static async signout() {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/**
|
||||
/*
|
||||
* Configures Passport Strategies
|
||||
*/
|
||||
'use strict'
|
||||
@@ -31,7 +31,7 @@ module.exports = ({
|
||||
throw new Error('functions must be a an object')
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* Return functions ID property from a functions object
|
||||
*/
|
||||
passport.serializeUser((user, next) => {
|
||||
@@ -44,7 +44,7 @@ module.exports = ({
|
||||
})
|
||||
})
|
||||
|
||||
/**
|
||||
/*
|
||||
* Return functions from a functions ID
|
||||
*/
|
||||
passport.deserializeUser((id, next) => {
|
||||
|
||||
Reference in New Issue
Block a user