Skip to content
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

fix logout #92

Merged
merged 8 commits into from
Feb 15, 2023
Merged

Conversation

jacobcoro
Copy link
Contributor

@jacobcoro jacobcoro commented Feb 14, 2023

#41 (comment)

What's happening:

When we click 'logout' new requests from SWR (like to subscriptions) get sent out, and the cookie that just got deleted resets again.

Also, if we redirect the use to the login page right after signing out, the browser still somehow has the cookie, and our middleware detects that the user is still logged in and redirects right back to the dashboard.

I tried calling supabase.auth.logOut on the server side but that doesn't actually work. because supabase uses jwt tokens, all the serverside logout does it say 'I wont accept refresh tokens' but doesn't invalidate the current token.

Why the swr calls still have a token after it was just deleted is a mystery to me.

references:

https://stackoverflow.com/questions/72972086/cannot-log-out-user-on-the-server-side-next-js-and-supabase

signOut not deleting cookie

Closedsupabase/gotrue-js · #46 · Issue opened by gomflo on Jan 17 2021

I then tried manually setting the cookie from the backend during the 'logout' call. That also did not work. (in the screenshot above, notice deleted and expires are set.

So it turns out doing a fully server-side log out is not possible with supabase as far as I can tell.

But if we do the logout page redirect, at least we should be able to redirect to the login page and not have it immediately sign back in

Tomorrow I will try redirecting the user to a logout page, that then redirects to login after signing out. We should probably still call the server logOut function even though it really doesnt do much.

Using a logout redirect page seemed to work, after fixing up some of the logic around 'profile' fetching. I think that the profile not getting set to null properly before logout might have been the culprit for the lingering fetch calls that re-validated the cookie.

I updated to use SWR for the profile fetching, which might fix some of the other bugs we've been seeing around signin status.

Solution

The way I finally solved the the 'inflight requests are resetting cookie' issue is:
calling window.location.href= "/logout" Then inside an empty pages/logout.tsx page, I call the auth.signOut function again and then finally redirect back to "/login" or "/signup"

The reason this works is that window.location.href will cancel in-flight requests, whereas router.push() in next.js will not.

also had to add an abort controller on one fetch request that I couldn't stop because its called from the top level _app.tsx
https://frontend-digest.com/cancelling-fetch-requests-in-react-applications-58a52a048e8e

@vercel
Copy link

vercel bot commented Feb 14, 2023

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Comments Updated
relay-supa-club ✅ Ready (Inspect) Visit Preview 💬 Add your feedback Feb 15, 2023 at 9:01AM (UTC)

Copy link

@pullrequest pullrequest bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ This pull request was sent to the PullRequest network.


Check the status or cancel PullRequest code review here.

Copy link

@pullrequest pullrequest bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PullRequest Breakdown

Reviewable lines of change

+ 193
- 72

55% TSX
45% TypeScript

Type of change

Fix - These changes are likely to be fixing a bug or issue.

Copy link

@pullrequest pullrequest bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These changes—primarily related to logout—look good to me. I had a few questions and comments inline.

Image of Ryan B Ryan B


Was this helpful? Yes | No

Reviewers will be notified any time you reply to their comments or commit new changes.
You can also request a full follow-up review from your PullRequest dashboard.

middleware.ts Outdated
*/
'/((?!_next/static|_next/image|favicon.ico|assets/*|api/company/accept-invite*|api/company/create-employee*).*)',
'/((?!_next/static|_next/image|favicon.ico|assets/*|api/company/accept-invite*|api/company/create-employee*|logout/*).*)',
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a bit unfortunate, since it likely won't be the last bug that gets created due to this approach. It's too bad Next doesn't seem to give many other options if you want to do the config approach, and it can't be from dynamic values.

If this list continues to grow, it might be worth handling these routes in the middleware function. As part of that, something should be done about the fact that this is tribal knowledge.

Meaning—other developers working on this code base have nothing telling them that adding a new "public / unauthed" route will break unless they know to come and add a regex to this line hiding at the bottom of the middleware file. How that gets addressed depends on the project conventions, but a comment in a well-placed location would at least help a little.

🔸 Reduce Future Bugs (Important)

Image of Ryan B Ryan B

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good point. I made a note in the middleware jsdoc, although it isnt ideal, someone new will definitely have to have a glance at this file during onboarding

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That sounds like a good improvement!

Image of Ryan B Ryan B

if (req.method === 'GET') {
const { id } = req.query as ProfileGetQuery;

if (!id) {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's good to see this pattern of validation after using a type assertion continuing to be applied.

◽ Compliment

Image of Ryan B Ryan B

if (!id) {
return res.status(httpCodes.BAD_REQUEST).json({ message: 'missing id' });
}
try {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are some opportunities for code reuse in this handler.

🔹 Code Reuse (Nice to have)

Image of Ryan B Ryan B

@@ -0,0 +1,14 @@
import { GetServerSidePropsContext } from 'next';
import { logoutRedirect } from 'src/utils/auth';
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What exactly is this route accomplishing that's different from just /logout?

🔸 Clarify Intent (Important)

Image of Ryan B Ryan B

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

redirecting to the login page with the old email pre-filled

const [loading, setLoading] = useState(false);
const [signupSuccess, setSignupSuccess] = useState(false);
const [initialLoad, setInitialLoad] = useState(true);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's great to see this being removed.

◽ Compliment

Image of Ryan B Ryan B


useEffect(() => {
// this fixes a bug where the profile is not loaded on the first page load when coming from signup
if (!loading && !profile?.id) refreshProfile();
}, [refreshProfile, profile, loading]);

const supabase = useSupabaseClient();
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Awesome to see supabase being abstracted away from here into an auth layer.

◽ Compliment

Image of Ryan B Ryan B

@@ -27,3 +48,23 @@ export const isCompanyOwnerOrRelayEmployee = async (req: NextApiRequest, res: Ne

return isAdmin(profile?.role);
};

export const logoutRedirect = async (ctx: GetServerSidePropsContext, email?: string) => {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a nicely written function.

◽ Compliment

Image of Ryan B Ryan B

Copy link

@pullrequest pullrequest bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The reason this works is that window.location.href will cancel in-flight requests, whereas router.push() in next.js will not.

This is expected, since the router is just for client-side routing within the same document, whereas window.location.href is an actual navigation event in which a new document is loaded.

Image of Ryan B Ryan B


Was this helpful? Yes | No

Reviewers will be notified any time you reply to their comments or commit new changes.
You can also request a full follow-up review from your PullRequest dashboard.

await supabaseClient.auth.signOut();
setProfile(null);
const email = session?.user?.email;
// cannot use router.push() here because it won't cancel in-flight requests which wil re-set the cookie
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great comment here. I was just getting ready to say "why can't we use the router" as I saw it.

◽ Compliment

Image of Ryan B Ryan B

@jacobcoro jacobcoro merged commit 0491557 into main Feb 15, 2023
@jacobcoro jacobcoro deleted the jacob/v2-72-logout-user-serverside-not-clientside branch February 15, 2023 09:06
Copy link

@pullrequest pullrequest bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey @jacobcoro,
Was the feedback from PullRequest helpful? Yes | No

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants