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

Next.js authMiddleware requires an 'afterAuth' function to redirect to user page, after Google social login #1477

Closed
4 of 20 tasks
jstlaurent opened this issue Jul 12, 2023 · 25 comments
Labels
nextjs prioritized This issue has been triaged and the team is working on it

Comments

@jstlaurent
Copy link

jstlaurent commented Jul 12, 2023

Package + Version

  • @clerk/clerk-js
  • @clerk/clerk-react
  • @clerk/nextjs
  • @clerk/remix
  • @clerk/types
  • @clerk/themes
  • @clerk/localizations
  • @clerk/clerk-expo
  • @clerk/backend
  • @clerk/clerk-sdk-node
  • @clerk/shared
  • @clerk/fastify
  • @clerk/chrome-extension
  • gatsby-plugin-clerk
  • build/tooling/chore
  • other:

Dependencies + versions

"dependencies": {
    "@clerk/nextjs": "^4.21.14",
    "next": "^13.4.5",
    "react": "^18.2.0",
  },

Browser/OS

Firefox 115.0.1

Description

Context

I've configured my Clerk app to use Google as a social login provider.

I've setup a simple Next.js app, using the new App Router, with a user page I've configured the auth middleware like this:

import { authMiddleware } from "@clerk/nextjs";

export default authMiddleware({
  publicRoutes: ["/", "/api"],
});

export const config = {
  matcher: ["/((?!.*\\..*|_next).*)", "/", "/(api|trpc)(.*)"],
};

I've created a user page (mapped to /user), like so:

import { UserProfile } from "@clerk/nextjs";

export default function UserPage() {
  return <UserProfile />;
}

I have a header component that uses Clerk's own SignInButton component, that looks like this:

"use client";
import { SignedOut, SignInButton, UserButton } from "@clerk/nextjs";
import Navigation from "@/components/Navigation";

export function Header() {
  return (
    <header className="container z-40 bg-background">
      <div className="flex h-20 items-center justify-between py-6">
        <Navigation />
        <nav>
          <SignedOut>
            <SignInButton
              mode="modal"
              afterSignInUrl="/user"
              afterSignUpUrl="/user"
            >
                Sign In
            </SignInButton>
          </SignedOut>
          <UserButton
            afterSignOutUrl="/"
            showName={true}
            userProfileMode="navigation"
            userProfileUrl="/user"
          />
        </nav>
      </div>
    </header>
  );
}

Problem

Running locally, if I click on the SignInButton in my header, then pick Google to login, I go through a successful OAuth login flow and get redirected to https://localhost:3000/user, but the following warning is displayed in the console:

INFO: Clerk: The request to /user is being redirected because there is no signed-in user, and the path is not included in `ignoredRoutes` or `publicRoutes`. To prevent this behavior, choose one of:

1. To make the route accessible to both signed in and signed out users, add "/user" to the `publicRoutes` array passed to authMiddleware
2. To prevent Clerk authentication from running at all, pass `ignoredRoutes: ["/((?!api|trpc))(_next|.+\..+)(.*)", "/user"]` to authMiddleware
3. Pass a custom `afterAuth` to authMiddleware, and replace Clerk's default behavior of redirecting unless a route is included in publicRoutes

However, I can modify the authMiddleware usage to be this:

export default authMiddleware({
  afterAuth: (auth) => {
    console.log("afterAuth", auth);
  },
  publicRoutes: ["/", "/api"],
});

And in that case, the redirect functions correctly, sending me to the user page, displaying Clerk's UserProfile component.

The strangest part, to me at least, is that the auth object logged to the console appears to be empty:

afterAuth {
  sessionClaims: null,
  sessionId: null,
  session: null,
  userId: null,
  user: null,
  actor: null,
  orgId: null,
  orgRole: null,
  orgSlug: null,
  organization: null,
  getToken: [Function: getToken],
  debug: [Function],
  isPublicRoute: false,
  isApiRoute: false
}

I can live with a bogus function in the middleware definition, if that fixes it, but it feels like I'm missing something here.

@clerk-cookie
Copy link
Collaborator

This issue is stale because it has been open 30 days with no activity. Remove stale label or comment or this will be closed in 10 days.

@jstlaurent
Copy link
Author

I'll update to latest and see if the issue persists.

@jescalan
Copy link
Contributor

@jstlaurent is there any chance you'd be willing to put together a minimal reproduction for this? This would help us to look into it - so sorry for the slow response!

@jescalan jescalan added the needs-reproduction Awaiting a minimal reproduction label Aug 25, 2023
@MichelML
Copy link

MichelML commented Sep 6, 2023

+1 for this

@dimkl
Copy link
Contributor

dimkl commented Sep 6, 2023

Kind reminder, to use the latest version of @clerk/nextjs, as it may resolve the issue.

@jstlaurent
Copy link
Author

jstlaurent commented Sep 6, 2023

Hi @jescalan! Sorry for the delay. I've created a repro case in this repo: https://github.com/jstlaurent/issue-1477

I initialized a basic Next.js app (using npx create-next-app@latest, picking default options), and then followed the steps outlined in Clerk's documentation here.

It's using a Clerk project created here, with Google as an SSO provider and all default options.

My only change to the Clerk quickstart was to add a /user path, and configure a post-signup, post-signin redirect to that page. I defined that redirect both in the .env.local env variables, but also on Clerk's <SignIn/> and <SignUp/> components.

I'm running Node 18.16.0, and I'm running the locally app with npm run dev.

My expectations would be that, after signing up through Google, I would be redirected to the user page.

The result is that I'm being returned to the root page.

Let me know if I can be of further assistance in clarifying what's happening.

@freightcrossings

This comment was marked as off-topic.

@freightcrossings

This comment was marked as off-topic.

@freightcrossings

This comment was marked as off-topic.

@freightcrossings

This comment was marked as off-topic.

@freightcrossings

This comment was marked as off-topic.

@jescalan
Copy link
Contributor

jescalan commented Sep 7, 2023

Hey @freightcrossings! I'm so sorry you have been running into these issues, and really appreciate the digging you have done to try to solve this. In this case, it would be better if you could open a new issue for your use case here, since this is a different issue, despite it seeming to be related. Including a reproduction as this issue's author has done would also help us much more to investigate.

@clerk-cookie
Copy link
Collaborator

Hello 👋

We currently close issues after 40 days of inactivity. It's been 30 days since the last update here. If we missed this issue, please reply here. Otherwise, we'll close this issue in 10 days.

As a friendly reminder: The best way to see an issue fixed is to open a pull request. If you're not sure how to do that, please check out our contributing guide.

Thanks for being a part of the Clerk community! 🙏

@jstlaurent
Copy link
Author

I submitted a repro case in my last message above.

@clerk-cookie clerk-cookie removed the Stale label Oct 9, 2023
@AyushChamoli961
Copy link

AyushChamoli961 commented Oct 13, 2023

Facing exactly same issue with "next": "13.4.19" and clerk "@clerk/nextjs": "^4.25.3". Please update if any solution found.

The problem only occurs on macos , I tried setting up clerk auth on my linux machine and it works fine but on macos I face the same problem as stated above.

@waldothedeveloper
Copy link
Contributor

This is happening to me as well, I just added the code afterAuth: (auth) => { console.log("afterAuth", auth); }, to the middleware as @jstlaurent suggested, and my error is now gone!

@jstlaurent
Copy link
Author

This is happening to me as well, I just added the code afterAuth: (auth) => { console.log("afterAuth", auth); }, to the middleware as @jstlaurent suggested, and my error is now gone!

@waldothedeveloper: I discovered afterwards that doing that seems to break the check that prevents non-authenticated users from accessing the protected pages of you application. I ended up removing the function and living with the failed redirect in local development.

@aakash19here
Copy link

import { authMiddleware } from "@clerk/nextjs";
import { NextResponse } from "next/server";

export const runtime = "nodejs";

export default authMiddleware({
  publicRoutes: [
    "/",
    "/sign-in(.*)",
    "/sign-up(.*)",
    "/api(.*)",
  ],
  async afterAuth(auth, req) {
    if (auth.isPublicRoute) {
      //  For public routes, we don't need to do anything
      return NextResponse.next();
    }

    const url = new URL(req.nextUrl.origin);

    if (!auth.userId) {
      //  If user tries to access a private route without being authenticated,
      //  redirect them to the sign in page
      url.pathname = "/sign-in";
      return NextResponse.redirect(url);
    }
  },
});

export const config = {
  matcher: ["/((?!.*\\..*|_next).*)"],
};

Hey @jstlaurent this approach worked for me

@jstlaurent
Copy link
Author

@aakash19here : Thanks for that! I feel the documentation could be clearer that you have to handle all cases when you choose to implement afterAuth. That tripped me.

@BaDo2001
Copy link

@aakash19here Huge kudos, the runtime export was missing in my case.

@jescalan jescalan added needs-triage A ticket that needs to be triaged by a team member linear Created by Linear-GitHub Sync and removed needs-reproduction Awaiting a minimal reproduction labels Nov 16, 2023
@jescalan
Copy link
Contributor

Sorry for the slow response here friends, we will discuss this one in the next couple days!

@merveillevaneck
Copy link

merveillevaneck commented Nov 19, 2023

I agree with a lot of the engineers who commented above. Above having searched through this thread, implementing a custom after auth function seems to make Next 14 + TRPC + clerk work normally. While this may not be something that HAS to be fixed, what would be awesome is just mentioning in the docs that it might be necessary for TRPC users to add that implementation. in most of the above cases I believe that the following snippet will work:

export default authMiddleware({
  publicRoutes: ["/"],
  afterAuth: (auth, req) => auth.isPublicRoute ? NextReponse.next() : undefined
  })

This essentially just makes clerks middleware respond appropriately. However, the error that is communicated by the clerk lib on the server side seems to suggest that only adding a path to the publicRoutes array should do the trick. but it does not.

@jescalan jescalan added prioritized This issue has been triaged and the team is working on it and removed needs-triage A ticket that needs to be triaged by a team member linear Created by Linear-GitHub Sync labels Nov 27, 2023
@LekoArts LekoArts added the nextjs label Dec 6, 2023
@LekoArts
Copy link
Member

LekoArts commented Dec 6, 2023

Hello @jstlaurent,

I tried your provided reproduction and with some changes I applied it works for me:

I added a .env.local file as following:

NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=your-key
CLERK_SECRET_KEY=your-key
NEXT_PUBLIC_CLERK_SIGN_IN_URL=/sign-in
NEXT_PUBLIC_CLERK_SIGN_UP_URL=/sign-up

Then changed these files:

diff --git a/package.json b/package.json
index dfd7730..9f3988f 100644
--- a/package.json
+++ b/package.json
@@ -9,14 +9,14 @@
     "lint": "next lint"
   },
   "dependencies": {
-    "@clerk/nextjs": "^4.23.5",
+    "@clerk/nextjs": "^4.27.4",
     "@types/node": "20.5.9",
     "@types/react": "18.2.21",
     "@types/react-dom": "18.2.7",
     "autoprefixer": "10.4.15",
     "eslint": "8.48.0",
-    "eslint-config-next": "13.4.19",
-    "next": "13.4.19",
+    "eslint-config-next": "^14.0.3",
+    "next": "^14.0.3",
     "postcss": "8.4.29",
     "react": "18.2.0",
     "react-dom": "18.2.0",
diff --git a/src/middleware.ts b/src/middleware.ts
index 89801cf..7ff0010 100644
--- a/src/middleware.ts
+++ b/src/middleware.ts
@@ -3,9 +3,11 @@ import { authMiddleware } from "@clerk/nextjs";
 // This example protects all routes including api/trpc routes
 // Please edit this to allow other routes to be public as needed.
 // See https://clerk.com/docs/references/nextjs/auth-middleware for more information about configuring your middleware
-export default authMiddleware({});
+export default authMiddleware({
+  publicRoutes: ['/', '/sign-in', '/sign-up']
+});
 
 export const config = {
-  matcher: ["/((?!.*\\..*|_next).*)", "/", "/(api|trpc)(.*)"],
+  matcher: ['/((?!.+\\.[\\w]+$|_next).*)', '/', '/(api|trpc)(.*)'],
 };

I don't see any warnings in my console nor that it doesn't work. Can you please verify on your end if with my updates it works for you?

@jstlaurent
Copy link
Author

@LekoArts : Thanks for taking the time to look into this! I'll be honest, our login flow has changed since I filed this issue so this is no longer a problem for us even if it was still happening. Maybe something got fixed in a library update along the way. I'll close the issue.

@clerk-cookie
Copy link
Collaborator

This issue has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.

@clerk clerk locked as resolved and limited conversation to collaborators Dec 7, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
nextjs prioritized This issue has been triaged and the team is working on it
Projects
None yet
Development

No branches or pull requests