-
-
Notifications
You must be signed in to change notification settings - Fork 3.6k
This issue was moved to a discussion.
You can continue the conversation there. Go to discussion →
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
make updating session easier #2269
Comments
Hi, and thanks for opening this. So when the session value changes and is being persisted either in a database or in the HttpOnly session cookie as JWT, the value can only be written server-side, so a trip to the server is inevitable. But I think we could expose a new function, something like const { data: session, update } = useSession()
...
const handleUpdate = async () => {
update((prev) => {...prev: foo: "new session value"})
}
I am currently refactoring the Would like to know what you think, and if you would be willing to open a PR for this @phileasmah |
Hi, glad you liked my idea, didn't know it could only be written server-side, but yea, what you suggested was exactly what I was thinking about! I'm just a student but would love to take another look and possibly open a PR for this. I'm trying to set up my local environment and was just wondering how I should go about trying to implement this with your refactoring in #2236 or should I just try to implement this without your refactor? |
I'll try to get it done this week, so hopefully you will be able to use the I think we will need a new endpoint for this, or we have to extend this one: https://github.com/nextauthjs/next-auth/blob/main/src/server/routes/session.js |
I'm guessing we could just have a Personally, I think a new endpoint would be better overall for readability, maintenance and maybe performance(?) since I don't think much would be needed to change data in the session as opposed to validating/refreshing it. |
This comment has been minimized.
This comment has been minimized.
@dkleber89 Please choose the alternative, or consider contributing through a PR 🙏. The show must go on! (For a more serious answer, this is not mine or anyone's application/library. We are open-source, with a license that lets you do anything at all with the source code. If you feel the development is a bit slow on features you need for your company's success, please ask them to consider sponsoring us, drive this conversation with your implementation suggestions, or create the feature yourself in your own fork, and open a PR back here, so others can make use of it as well! Please remember that for now only we work on this project in our free time, and although we would like to prioritize every user's wishes, we simply cannot. Thanks for understanding 💚) |
Thanks for your feedback ... It was not a reproach or something else ... Was only a question for my interrest ... I know also the open source meaning and how it works but unfortunately this discussion is a hard one in the company i work :-( |
I see. This is mainly only an issue with the JWT persisted session flow. If you use a database, you can update the data directly, and if you configured it correctly, I believe the With the proposed method in this discussion, it would be up to you to update the cookie on-demand, for example when you know that the user info has changed. |
I am using JWT and have a need to update the session (after onboarding). I implemented this "hack" to get proper cookie with JWT. Current No relogin by user needed. Update api/auth/[...nextauth].ts handler: export default async (req: NextApiRequest, res: NextApiResponse) => {
if (req.url === "/api/auth/session?update") {
// Session call updates cookie, redirect to / afterwards
const endResponse = res.end as (cb?: () => void) => void;
res.end = (cb: () => void) => {
res.setHeader("Location", "/");
res.status(301);
return endResponse.apply(res, [cb]);
};
return NextAuth(req, res, options);
} else {
return NextAuth(req, res, options);
}
} When needed, forward user to |
Not sure I understand @huksley. How would that retrieve the new information about a user from an OAuth provider? I'm not really sure what it actually does either. So if NextAuth calls res.end, you redirect to the homepage? Why? Could you please explain? 😊 |
This comment has been minimized.
This comment has been minimized.
So this issue was actually meant to discuss how we could improve the current implementation, not individual questions for one's own problems. I understand it is frustrating, but please open a discussion with your problem rather than asking for help here as this does not accelerate the resolving of this issue. We welcome any implementation suggestions or PRs regarding this. Thanks for understanding! 🙏💚 |
@phileasmah #2236 is now merged, so if you want to have a look at it and create a PR, please do. I'll try looking at this myself whenever I get the time. |
@balazsorban44 If you need to fetch something from OAuth provider, you can do it manually or in Current implementation of next-auth/src/server/routes/session.js Line 55 in 2155c93
My "hack" is to avoid outputting JSON and instead forward user to other page, as needed. |
And what other page would you send the user? and why? I am just curious to understand. |
I think this is out of scope of this issue, but for my use case is I avoid hitting the DB on every API request, instead I keep in JWT token everything needed to check permissions. For this I have user.companyId which is created by user after login using OAuth. In this scenario I need a way to update the JWT token without relogin. After that I redirect to dashboard. |
@huksley it's working for me but only the first time. Flow is : 1) user submits profile form 2) redirection with Next times Making a XHR to const createOptions = req => ({
// ...
callbacks: {
async jwt(params) {
if (req.url === "/api/auth/session?update") {
// hit the DB and return token with updated values
}
}
}
});
export default async (req, res) => {
return NextAuth(req, res, createOptions(req));
}; |
I'd like to see something such as: const [session, isLoading, refresh] = useSession({ setLoadingAfterInit: false }) This way when a user update their username or other attributes we can trigger the |
I am new to next auth and now need to mutate the session. It's easier store the new value to db and then do something like this I think. Or |
@balazsorban44 hey I just wanted to check if this feature is definitively on the roadmap or not, it seems like things may have gotten bogged down in the implementation details. FWIW, the implementation you described here #2269 (comment) sounds great to me and would be extremely useful. |
Yeah, I do plan to add something like this, but I don't have an ETA. Currently busy getting v4 and all the relevant database adapters to stable. 👍 I don't want to start working on new features at this point, because then I would never release v4. 😅 I have a TON of ideas for improvements... 👀 |
Ok cool, thanks for confirming. Appreciate your work and looking forward to the updates! |
@balazsorban44 Just want to get a confirm. It is impossible to mutate session without logout/login currently for V3 right ? |
I'd like to see this feature added soon where my application constantly updates user's profile and I don't want to hit the profile apis on every session requests. |
Actually this method is working for me if you combine it with a session callback. So a simple working example: const createOptions = (req) => ({
// ...
callbacks: {
async jwt({ token, ...params }) {
if (req.url === "/api/auth/session?update") {
// hit the DB and return token with updated values. e.g.:
token.name = "Updated Mr. Johnson";
}
return token;
},
async session({ session, token }) {
console.log(token);
session.user = {
...session.user,
name: token.name
}
return session;
},
},
});
export default async (req, res) => {
return NextAuth(req, res, createOptions(req));
}; Then somewhere in your client you can make an AJAX call to the |
How to update user object inside the session after user edits his profile? Is this the official way to do it, it's really ugly? if (req.url === "/api/auth/session?update") {
... |
I end up don't store any user info into the session except the crtical rotation and secret token, those will be stably rotate checked via next auth, then retrieved and replaced from auth api whenever user open the app. Use another user api to retrieve up to date user info as application change. Save it somewhere else temporarily acrossing the entire app using, or in local storage if you really want to. There are many ways to avoid abusing the user info api, which I found much more stable comparing to hack through the session here. And avoid the hazard of messing with token. |
Please don't use local storage for storing user information. |
You are right. I probably should state more explicitly the data and the degree of security measure without misleading others. |
I am doing like this, but everytime i navigate to another page/refresh, the token and session values go back the previous ones. Even though the database has been updated. |
I've added a XHR call in session callback to get new data from DB each time. But data on front only update if I click on another tab then on the Nextjs one. Is there a way to make this directly happen on my page ? Calling callbacks.session = async function session({ session, token }) {
session.user = token.user;
session.jti = token.jti;
// If user is logged, we refresh his session
if (token?.user?.id) {
const url = routes.api.entities.shop.get.byId.build(token?.user?.id);
let apiResp = await axios.get(url, {});
session.user = { ...apiResp.data };
token.user = { ...apiResp.data };
}
return session;
}; |
Same here! |
Have a look here : #596 |
Hi everyone, I just wanted to let you know, that I've had some progress on this. Please see #3648, there is an experimental release available there as well. The API is const updateUser = (user: Partial<User>) => Session["user"] Example to update <form
onSubmit={async (e) => {
e.preventDefault()
const form = new FormData(e.target)
const user = Object.fromEntries(form.entries())
await updateUser(user)
e.target.reset()
}}
>
<input name="name" />
<button>Update</button>
</form> There are caveats though:
1 is probably debatable, if someone gives me a good argument I can think about it |
This is awesome! can't wait for this to be released :) |
I'm still thinking through 3. and 4. It feels a bit weird, but I don't think we could enforce a format like that without a breaking change... 🤔 For 3, we might just introduce a new hook that could return the access_token for any of the Accounts saved in the db, finally adding token rotation support at the same time. For 4, we could add a feature flag maybe, and a warning/error when using that method incorrectly (without having a |
That sounds great. Thanks! |
So to be clear, does this mean that it is currently not possible to mutate the values within JWT, and persist them? |
So far I store only immutable user properties in session like userId and sync the rest of the user object with GET user/:id endpoint and React Query. Is there a better way? |
This issue was moved to a discussion.
You can continue the conversation there. Go to discussion →
Discussed in #2267
Originally posted by phileasmah June 28, 2021
Summary 💭
Include a
setState
to mutate thesession
state when using theuseSession()
hook.Description 📓
In my app, I'm trying to build a settings page for profiles, like changing the display name etc, but I found that after changing the display name (name in database has been changed), the
session
state inuseSession()
stayed the same.So, I was trying to find a way to mutate the session object of the current user and stumbled upon
getSession()
which (correct me if I'm wrong) is suppose to get a new session and replace it with the current one but according to thisissue
it doe not work as intended.I was looking at the source code and thought wouldn't it be easier to just allow us to mutate the session state directly? (or are there security concerns I'm not aware of? In which case, it would be interesting to know). Looking at the code, it should be pretty easy to implement.
An advantage when compared to
getSession()
would obviously be that 1 less call needs to be made to the database, but again, I'm not sure if I am glossing over any security concerns etcThere are probably other related issues, which could be resolved with this. I'll try to gather them below, but if anyone reading this knows any, please comment below, and I would also like to hear your thoughts on this!
The text was updated successfully, but these errors were encountered: