Next-auth: Callbacks for login / logout events

Created on 4 May 2020  路  9Comments  路  Source: nextauthjs/next-auth

It would be really useful to be able to register middleware / handlers to be processed after the various types of next-auth event, e.g.:

  • Successful login (and via which mechanism)
  • Failed login
  • Logout
  • Password recovery / email token generation
  • ...

This is useful for things like audit logging, cleaning up resources etc.

Some of this can already be achieved with standard express middleware patterns (though can be a little clunky to handle all of the potential routes). However, some paths such as logout are much harder to handle properly without forking next-auth.

@iaincollins -- would it be possible to get something like this in to the upcoming rewrite (Version 2.0)?

enhancement

Most helpful comment

Absolutely, this is a great idea! Those are easy for me to do, and it's a lot easier than defining your own routines for creating and updating user accounts, etc and I imagine it would solve problems for a lot of folks.

I've just updated the NextAuth 2.0 announcement with more details about configuration and database integration, which I think will be relevant!

Things are a lot simpler in 2.0 and it's now possible to expose this without folks having to write their own database integration, which probably won't be needed now that different database back ends are supported out of the box (but you can still do that).

I would imagine we'd need to support before and after handlers for the following events:

```javascript
async function createUser() { }
async function updateUser() { }
async function getUserById() { }
async function getUserByProviderAccountId() { }
async function getUserByEmail() { }
async function getUserByCredentials() { }
async function deleteUserById() { }
async function linkAccount() { }
async function unlinkAccount() { }
async function createSession() { }
async function getSessionById() { }
async function deleteSessionById() { }
````

This is a work in progress list. I will try to come back to this and update it if things change. There are more events than there are in v1.x but I've done that as these are much simpler functions and so easier to cater for (having only a few functions in v1.x actually made things more complicated).

User and Session objects and schemas are also clearly defined in 2.0 (and you can customise them provide your own), so working with callbacks should be a lot easier.

It would be helpful if people would can comment on a list of events or middleware functions they would like to see, and what they would like them to pass (e.g. full User object, the raw Profile object from oAuth provider, additional details for the oAuth provider, etc) I'm happy to implement that.

All 9 comments

Absolutely, this is a great idea! Those are easy for me to do, and it's a lot easier than defining your own routines for creating and updating user accounts, etc and I imagine it would solve problems for a lot of folks.

I've just updated the NextAuth 2.0 announcement with more details about configuration and database integration, which I think will be relevant!

Things are a lot simpler in 2.0 and it's now possible to expose this without folks having to write their own database integration, which probably won't be needed now that different database back ends are supported out of the box (but you can still do that).

I would imagine we'd need to support before and after handlers for the following events:

```javascript
async function createUser() { }
async function updateUser() { }
async function getUserById() { }
async function getUserByProviderAccountId() { }
async function getUserByEmail() { }
async function getUserByCredentials() { }
async function deleteUserById() { }
async function linkAccount() { }
async function unlinkAccount() { }
async function createSession() { }
async function getSessionById() { }
async function deleteSessionById() { }
````

This is a work in progress list. I will try to come back to this and update it if things change. There are more events than there are in v1.x but I've done that as these are much simpler functions and so easier to cater for (having only a few functions in v1.x actually made things more complicated).

User and Session objects and schemas are also clearly defined in 2.0 (and you can customise them provide your own), so working with callbacks should be a lot easier.

It would be helpful if people would can comment on a list of events or middleware functions they would like to see, and what they would like them to pass (e.g. full User object, the raw Profile object from oAuth provider, additional details for the oAuth provider, etc) I'm happy to implement that.

@iaincollins hey, I think the set you provided there suits us just fine :smiley: . We just need to hook into the ways a users session can be created and destroyed, and the various ways they can get logged in. This is to create an audit trail we can provide to customers

@iaincollins hi, appreciate when next-auth-2 is finally released there can be a quick guide about using it with passport.js.

Maybe you can have your own abstract layer like passport strategy that we can follow to extend (ie. keycloak)

@tanvp112 Hi there!

So, in order to keep things as light as possible NextAuth 2.0 does not use Express or Passport.js, but it does work in a similar way to Passport.

oAuth 1.x and oAuth 2.x are supported via the oauth NPM package, and NextAuth 2.0 supports different authentication libraries. Current beta releases only ship with one, as it works for oAuth 1.x and 2.x, but I have tried it with two different NPM oauth libraries and it works great with both.

Twitter, Facebook, GitHub, Google will all be supported out of the box, this is all that's needed:

import NextAuth from 'next-auth'
import Providers from 'next-auth/providers'
import Adapters from 'next-auth/adapters'

const options = {
  site: process.env.SITE_NAME || 'http://localhost:3000',
  providers: [
    Providers.Twitter({
      clientId: process.env.TWITTER_CLIENT_ID,
      clientSecret: process.env.TWITTER_CLIENT_SECRET,
    }),
    Providers.Google({
      clientId: process.env.GOOGLE_CLIENT_ID,
      clientSecret: process.env.GOOGLE_CLIENT_SECRET
    }),
    Providers.GitHub({
      clientId: process.env.GITHUB_CLIENT_ID,
      clientSecret: process.env.GITHUB_CLIENT_SECRET
    }),
    Providers.Facebook({
      clientId: process.env.FACEBOOK_CLIENT_ID,
      clientSecret: process.env.FACEBOOK_CLIENT_SECRET,
    }),
  ],
  adapter: Adapters.Default()
}

export default (req, res) => NextAuth(req, res, options)

All these functions actually do is return a JSON object like this - with any options passed to the functions overriding the default values. e.g. if you do console.log() on the response from Providers.Google() you will see this:

{
  id: 'google',
  name: 'Google',
  type: 'oauth',
  version: '2.0',
  scope: 'https://www.googleapis.com/auth/userinfo.profile https://www.googleapis.com/auth/userinfo.email',
  options: { grant_type: 'authorization_code' },
  accessTokenUrl: 'https://accounts.google.com/o/oauth2/token',
  requestTokenUrl: 'https://accounts.google.com/o/oauth2/auth',
  authorizationUrl: 'https://accounts.google.com/o/oauth2/auth?response_type=code',
  profileUrl: 'https://www.googleapis.com/oauth2/v1/userinfo?alt=json',
  profile: (profile) => {
    return {
      id: profile.id,
      name: profile.name,
      email: profile.email,
      image: profile.picture
    }
  },
  clientId: '',
  clientSecret: ''
}

So, you can simply pass your own configuration object here for an oAuth 1.0, 1.0A or 2.0 provider and it should work.

It's good to bring up Keycloak as I got a lot of requests about support it, and it was a real pain to get working with NextAuth 1.x, due to interoperability issues between NextAuth, Passport.js and the strategies for Keycloak people were using (the oAuth standard is quite loose and doesn't define everything, so problems are quite common).

This should be much easier to deal with in NextAuth 2.0 there is less abstraction than with Passport.js, which is what caused the interoperability issues. It would be great to support Keycloak out of the box if someone could help with that!

I'm more than happy to add callbacks / middleware options to providers if it would help facilitate this.

@iaincollins, thanks for the detailed explanations, you are amazing! i look forward to the release of next-auth-2 and will tryout the mixin idea with keycloak-connect-nodejs.

Thanks again.

You're welcome! I have an example repo I've been meaning to upload if that would be helpful.

In theory it should be possible to just pass a well formed config object for a Keycloak service and it should "just work", but I don't know what that looks like, what options are needed or how standard it is and I don't have any way to test it.

If you can figure out the options and a working config on your system and are happy to share it (with any private details removed) I'd be happy to add it and release it in a new beta as supported 'provider' for folks to try out.

For the existing profiles, I got a lot of the info from looking at the source of the Passport.js strategies for them, as the documentation for each provider often wasn't very good!

@iaincollins, where can I find this example repo; I am happy to give it try and share it out.

@tanvp112 I've just created/updated How to clone / contribute to next-auth? with instructions, should have everything you need!

Closing - this issue can now be tracked in #247

Was this page helpful?
0 / 5 - 0 ratings

Related issues

jimmiejackson414 picture jimmiejackson414  路  3Comments

eatrocks picture eatrocks  路  3Comments

alephart picture alephart  路  3Comments

MelMacaluso picture MelMacaluso  路  3Comments

iaincollins picture iaincollins  路  3Comments