Now passes oAuth profile to insert() and update()

The oAuth profile for a service is now passed to update() and insert() when signing in via oAuth (or linking accounts).

e.g. `update(user, oAuthProfile)` and `insert(user, oAuthProfile)`

This provides a way to also capture oAuth provider specific fields, such as avatar, location, organisation, etc. as needed.

Thanks to @gielcobben for raising this.
This commit is contained in:
Iain Collins
2018-02-02 18:04:13 +00:00
parent 5fe3f09d47
commit afcae75aaf
6 changed files with 50 additions and 27 deletions

View File

@@ -115,10 +115,10 @@ You can add the following to your `package.json` file to start the project:
You will need to create following pages under `./pages/auth` in your project:
* index.js // Sign In
* index.js // Sign In (and Link/Unlink)
* error.js // Error handling
* check-email.js // Check email prompt
* callback.js // Callback page for Single Page Apps
* callback.js // Callback page, used to update state in Single Page Apps
You can [find examples of these](https://github.com/iaincollins/next-auth/tree/master/example) included which you can copy and paste into your project.
@@ -162,8 +162,8 @@ 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**
* find({id,email,emailToken,provider})
* insert(user)
* update(user)
* insert(user, oAuthProfile)
* update(user, oAuthProfile)
* remove(id)
* serialize(user)
* deserialize(id)

View File

@@ -102,7 +102,7 @@ module.exports = () => {
} else if (emailToken) {
query = { emailToken: emailToken }
} else if (provider) {
query = { [`${provider.name}.id`]: provider.id }
query = { [`${provider.name}.id`]: provider.id }
}
return new Promise((resolve, reject) => {
@@ -112,7 +112,14 @@ module.exports = () => {
})
})
},
insert: (user) => {
// The user parameter contains a basic user object to be added to the DB.
// The oAuthProfile parameter is passed when signing in via oAuth.
//
// The optional oAuthProfile parameter contains all properties associated
// with the users account on the oAuth service they are signing in with.
//
// You can use this to capture profile.avatar, profile.location, etc.
insert: (user, oAuthProfile) => {
return new Promise((resolve, reject) => {
usersCollection.insert(user, (err, response) => {
if (err) return reject(err)
@@ -125,7 +132,14 @@ module.exports = () => {
})
})
},
update: (user) => {
// The user parameter contains a basic user object to be added to the DB.
// The oAuthProfile parameter is passed when signing in via oAuth.
//
// The optional oAuthProfile parameter contains all properties associated
// with the users account on the oAuth service they are signing in with.
//
// You can use this to capture profile.avatar, profile.location, etc.
update: (user, profile) => {
return new Promise((resolve, reject) => {
usersCollection.update({_id: MongoObjectId(user._id)}, user, {}, (err) => {
if (err) return reject(err)
@@ -133,6 +147,10 @@ module.exports = () => {
})
})
},
// The remove parameter is passed the ID of a user account to delete.
//
// This method is not used in the current version of next-auth but will
// be in a future release, to provide an endpoint for account deletion.
remove: (id) => {
return new Promise((resolve, reject) => {
usersCollection.remove({_id: MongoObjectId(id)}, (err) => {
@@ -145,15 +163,18 @@ module.exports = () => {
serialize: (user) => {
// Supports serialization from Mongo Object *and* deserialize() object
if (user.id) {
return Promise.resolve(user.id)
// Handle responses from deserialize()
return Promise.resolve(user.id)
} else if (user._id) {
// Handle responses from find(), insert(), update()
return Promise.resolve(user._id)
} else {
return Promise.reject(new Error("Unable to serialise user"))
}
},
// Deseralize turns a User ID into a normalized User object that is
// exported to clients. It should not return private/sensitive fields.
// exported to clients. It should not return private/sensitive fields,
// only fields you want to expose via the user interface.
deserialize: (id) => {
return new Promise((resolve, reject) => {
usersCollection.findOne({ _id: MongoObjectId(id) }, (err, user) => {

View File

@@ -17,7 +17,7 @@
"mongodb": "^3.0.1",
"nedb": "^1.8.0",
"next": "^4.2.3",
"next-auth": "^1.1.1",
"next-auth": "^1.3.0",
"next-auth-client": "^1.1.1",
"nodemailer": "^4.4.2",
"nodemailer-direct-transport": "^3.3.2",

View File

@@ -56,8 +56,8 @@ module.exports = (nextApp, {
emailToken,
provider // provider = { name: 'twitter', id: '123456' }
} = {}) => { Promise.resolve(user) },
update: (user) => { Promise.resolve(user) },
insert: (user) => { Promise.resolve(user) },
update: (user, profile) => { Promise.resolve(user) },
insert: (user, profile) => { Promise.resolve(user) },
remove: (id) => { Promise.resolve(id) },
serialize: (user) => { Promise.resolve(id) },
deserialize: (id) => { Promise.resolve(user) },
@@ -303,8 +303,9 @@ module.exports = (nextApp, {
functions.find({ emailToken: req.params.token })
.then(user => {
if (user) {
// Reset token and update email address as verified
user.emailToken = null
// 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 {

View File

@@ -1,6 +1,6 @@
{
"name": "next-auth",
"version": "1.2.1",
"version": "1.3.0",
"description": "An authentication library for Next.js",
"repository": "https://github.com/iaincollins/next-auth.git",
"main": "index.js",

View File

@@ -17,8 +17,8 @@ module.exports = ({
emailToken,
provider
} = {}) => {},
update: (user) => {},
insert: (user) => {},
update: (user, profile) => {},
insert: (user, profile) => {},
serialize: (user) => {},
deserialize: (id) => {}
}
@@ -69,11 +69,12 @@ module.exports = ({
strategyOptions.callbackURL = (serverUrl || '') + `${pathPrefix}/oauth/${providerName.toLowerCase()}/callback`
strategyOptions.passReqToCallback = true
passport.use(new Strategy(strategyOptions, (req, accessToken, refreshToken, profile, next) => {
passport.use(new Strategy(strategyOptions, (req, accessToken, refreshToken, _profile, next) => {
try {
// Normalise the provider specific profile into a standard user object.
profile = getProfile(profile)
// Normalise the provider specific profile into a standard basic
// profile object with just { id, name, email } properties.
let profile = getProfile(_profile)
// Save the Access Token to the current session.
req.session[providerName.toLowerCase()] = {
@@ -115,7 +116,7 @@ module.exports = ({
refreshToken: refreshToken
}
functions.update(user)
functions.update(user, _profile)
.then(user => {
return next(null, user)
})
@@ -133,7 +134,7 @@ module.exports = ({
// This prevents users from linking an oAuth account to more
// than one local account at the same time.
return next(null, false)
}
}
} else {
// This secion handles if a user is already logged in and is
// trying to link a new account.
@@ -177,7 +178,7 @@ module.exports = ({
}
// Update details for the new provider for this user.
return functions.update(user)
return functions.update(user, _profile)
.then(user => {
return next(null, user)
})
@@ -200,10 +201,10 @@ module.exports = ({
// as that user.
// Update Access and Refresh Tokens for the user if we got them.
if (accessToken || refreshToken) {
if (accessToken || refreshToken) {
if (accessToken) user[providerName.toLowerCase()].accessToken = accessToken
if (refreshToken) user[providerName.toLowerCase()].refreshToken = refreshToken
return functions.update(user)
return functions.update(user, _profile)
.then(user => {
return next(null, user)
})
@@ -234,7 +235,7 @@ module.exports = ({
// or create an account elsewhere for another users email
// address then trying to sign in from it, so don't do that.
if (user) return next(null, false)
// If an account does not exist, create one for them and return
// a user object to passport, which will sign them in.
return functions.insert({
@@ -245,7 +246,7 @@ module.exports = ({
accessToken: accessToken,
refreshToken: refreshToken
}
})
}, _profile)
.then(user => {
return next(null, user)
})