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.
It's a good question, the answer to which is this isn't documented yet and you can track it here:
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
Most helpful comment
@ndom91 related: https://github.com/nextauthjs/next-auth/issues/562#issuecomment-716740547
I'd prefer to use the
authorizefunction to extendusersince 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.userthroughout the app. I could make additional API call in thesessioncallback, but that assumes I have an endpoint likegetUserByRole, which I may not (role is returned when user gets authenticated).Thanks for your help!
EDIT: Given the docs for
authorizesay:// Any object returned will be saved inuserproperty of the JWTI 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.