Next-auth: What is the best way to extend a user profile?

Created on 23 Jun 2020  路  11Comments  路  Source: nextauthjs/next-auth

Your question
What is the best way to extend a user profile with custom fields?

What are you trying to do
I want to store more information about a user -- things like billing information, a username, etc. I would rather not build a whole new database adapter. I am okay with storing this information in a separate DB table, but curious if I can expose some form of unique ID that I can use as a primary key?

Are there recommended ways of doing this?

Documentation feedback
Documentation refers to searching through online documentation, code comments and issue history. The example project refers to next-auth-example.

  • [ ] Found the documentation helpful
  • [ ] Found documentation but was incomplete
  • [X] Could not find relevant documentation
  • [ ] Found the example project helpful
  • [ ] Did not find the example project helpful
question

Most helpful comment

@ndom91 related: https://github.com/nextauthjs/next-auth/issues/562#issuecomment-716740547

I'd prefer to use the authorize function to extend user since I have already made an API call here and have the relevant data accessible.

Would love to NOT delegate this to state managment (Redux, Apollo, etc) and instead rely on session.user throughout the app. I could make additional API call in the session callback, but that assumes I have an endpoint like getUserByRole, which I may not (role is returned when user gets authenticated).

Thanks for your help!

EDIT: Given the docs for authorize say:

// Any object returned will be saved inuserproperty of the JWT

I propose that be removed / edited to reflect the existing state where ONLY 3 fields are persisted on user: name, email, image. I could be mistaken, but believe this to be the case.

All 11 comments

It's a good question, the answer to which is this isn't documented yet and you can track it here:

  • Document how to use custom models #283

Closing this issue as tere is now official documentation on how to extend the user model, for example.

https://next-auth.js.org/tutorials/typeorm-custom-models

If you have any new question, etc. feel free to reopen it!

@ndom91

https://next-auth.js.org/tutorials/typeorm-custom-models shows config with database. Is it possible to extend the user model with Adapters and no DB? I tried passing null for DB url, but this failed.

IOW, I want to add a property like role to the user model client side only (this value is returned from custom auth provider API)?

@DeBraid

I know you can add properties to the session, and therefore the user object, in the session callback.

https://next-auth.js.org/configuration/callbacks#session-callback

Maybe that can help you along, sorry haven't done it myself so I can't say for sure what the best route would be.

@ndom91 related: https://github.com/nextauthjs/next-auth/issues/562#issuecomment-716740547

I'd prefer to use the authorize function to extend user since I have already made an API call here and have the relevant data accessible.

Would love to NOT delegate this to state managment (Redux, Apollo, etc) and instead rely on session.user throughout the app. I could make additional API call in the session callback, but that assumes I have an endpoint like getUserByRole, which I may not (role is returned when user gets authenticated).

Thanks for your help!

EDIT: Given the docs for authorize say:

// Any object returned will be saved inuserproperty of the JWT

I propose that be removed / edited to reflect the existing state where ONLY 3 fields are persisted on user: name, email, image. I could be mistaken, but believe this to be the case.

Hello,

I'd like to elaborate if this package can extend the profile with user roles: https://github.com/nextauthjs/next-auth/issues/312#issuecomment-671575050
I checked the documentation but for me following usecase is not clear:

- user modifies his roles through subscribing 
- refresh user credentials with new user roles and persist the roles in the database

How would the database would be updated? Or better how could the a server side callback adjust the user credentials and refetch the new data client side

@iaincollins do you have any suggestion on how best to manipulate the user object? With or without a db?

My current (hopefully very short term) work around involves hijacking the image property on session.user and assigning it the value for role which is returned by Auth API.

import fetch from 'isomorphic-unfetch';

import { API_ENDPOINT } from './constants';

export default async function login({ email, password }) {
  const body = {
    Email: email,
    Password: password,
  };
  const requestOptions = {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
    },
    body: JSON.stringify(body),
  };

  const response = await fetch(`${API_ENDPOINT}/users/login/`, requestOptions);
  const { user, error } = await response.json(); // user.role send from API response, need to store this on session.user somehow
  if (error) {
    return Promise.reject(`/login?error=${error}&email=${email}`);
  }
  const userToResolve = {
    email: user.Email,
    image: user.Role || 'user', // FIXME DB hack for next-auth user object, set image = role
  };
  return Promise.resolve(userToResolve);
}

Obviously, I don't want to do this, and would prefer simply adding role to userToResolve like so:

  ...
  const userToResolve = {
    email: user.Email,
    role: user.Role || 'user',
  };
  return Promise.resolve(userToResolve);
}

Despite extending the userToResolve object with arbitrary properties, the session.user persist only 3 fields: name, image, email.

EDIT: I am now using the jwt/session callback strategy shown below from @elilambnz https://github.com/nextauthjs/next-auth/issues/312#issuecomment-720203467

To extend the user without using a database, you can modify the JWT when it is created (i.e. when logging in for the first time), then update the session user from the extra data in the JWT. This is my solution:

callbacks: {
  jwt: async (token, user, account, profile, isNewUser) => {
    // The user argument is only passed the first time this callback is called on a new session, after the user signs in
    if (user) {
      // Add a new prop on token for user data
      token.data = user
    }
    return Promise.resolve(token)
  },
  session: async (session, user) => {
    // Assign user data from JWT to session user
    session.user = user.data
    return Promise.resolve(session)
  },
}

Note: it appears that the session callback gets called often, so updating the session user frequently may not be the best solution. I've only been using this library for a few hours, so I'm far from an expert on this!

Edit: Previously I had a more iterative solution, but have since updated this answer after seeing this solution on stackoverflow.

Can we re-open this ticket and get an official way to extend the user model when not using a DB? cc/ @ndom91 @iaincollins

@aequasi sure, but I think the only way to do this is in the JWT callback. See @elilambnz last post and the docs here: https://next-auth.js.org/configuration/callbacks#jwt-callback

Was this page helpful?
0 / 5 - 0 ratings

Related issues

iaincollins picture iaincollins  路  3Comments

simonbbyrne picture simonbbyrne  路  3Comments

readywater picture readywater  路  3Comments

benoror picture benoror  路  3Comments

Xetera picture Xetera  路  3Comments