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

Multi-tenants auth on subdomains via google with proxy results in a InvalidCheckError #12225

Open
Dragosp33 opened this issue Nov 12, 2024 · 0 comments
Labels
bug Something isn't working triage Unseen or unconfirmed by a maintainer yet. Provide extra information in the meantime.

Comments

@Dragosp33
Copy link

Dragosp33 commented Nov 12, 2024

Environment

  System:
    OS: Windows 10 10.0.19045
    CPU: (8) x64 AMD Ryzen 5 3550H with Radeon Vega Mobile Gfx  
    Memory: 11.13 GB / 21.93 GB
  Binaries:
    Node: 20.4.0 - C:\Program Files\nodejs\node.EXE
    Yarn: 1.22.21 - C:\Program Files\nodejs\yarn.CMD
    npm: 9.7.2 - C:\Program Files\nodejs\npm.CMD
  Browsers:
    Edge: Chromium (127.0.2651.74)
    Internet Explorer: 11.0.19041.4355
  npmPackages:
    next: 14.1.4 => 14.1.4
    next-auth: ^5.0.0-beta.25 => 5.0.0-beta.25
    react: ^18 => 18.3.1

Reproduction URL

https://github.com/Dragosp33/aws-auth-test/tree/main

Describe the issue

I'm trying to implement multi-tenants authentication on subdomains via google / github. As I can't add every tenant on google / github whitelist, I thought of using the redirectProxy ( example from the Securing Preview Guide ) with the main domain, where the auth is located ( http://localhost:3000 for local dev) . However, I'm getting this error when trying a google signin from a subdomain ( let's say http://subdomain1.localhost:3000 ):

[auth][error] InvalidCheck: state value could not be parsed. Read more at https://errors.authjs.dev#invalidcheck

The pcke_code and state cookies are added to the subdomain ( http://subdomain1.localhost:3000 ) and then I'm redirected to the main domain.

auth.config.ts:

import type { NextAuthConfig } from 'next-auth';
import Twitter from 'next-auth/providers/twitter';
import Google from 'next-auth/providers/google';
import GitHub from 'next-auth/providers/github';

const authConfig = {
  providers: [
    Google({
      clientSecret: process.env.AUTH_GOOGLE_SECRET,
      clientId: process.env.AUTH_GOOGLE_ID,
      allowDangerousEmailAccountLinking: true,
      //redirectProxyUrl: 'http://localhost:3000/api/auth',
    }),
    GitHub({
      clientSecret: process.env.GITHUB_SECRET,
      clientId: process.env.GITHUB_ID,
      allowDangerousEmailAccountLinking: true,
    }),
  ],
  pages: {
    signIn: '/auth/login',
    error: '/auth/error',
  },
  session: { strategy: 'jwt', maxAge: 60 * 60 * 24 * 7 },
  jwt: { maxAge: 60 * 60 * 24 },
  trustHost: true,
} satisfies NextAuthConfig;

export default authConfig;

auth.ts:

export const {
  handlers: { GET, POST },
  auth,
  signIn,
  signOut,
} = NextAuth(() => {
  const headersList = headers();
  const protocol = headersList.get('x-forwarded-proto');
  const host = headersList.get('host');
  const REDIRECT_URL =
    protocol && host
      ? `https://${host}/api/auth`
      : 'https://localhost:3000/api/auth';
  console.log('NEXT AUTH : ', REDIRECT_URL, headersList);
  return {
    ...authConfig,
    events: {
      async signIn({ user, profile, account }) {
        console.log('SIGN IN EVENT: ', { user, profile, account });
      },
      async updateUser({ user }) {
        console.log('UPDATE USER: ', { user });
      },
      async linkAccount({ user, profile, account }) {
        console.log('FROM LINK ACCOUNT: ', { user, profile, account });
      },
    },
    callbacks: {
      async signIn({ user, account, profile, email, credentials }) {
        console.log(user, account, profile, email);
        return true;
      },
    },
  };
});

middleware.ts:

import NextAuth from 'next-auth';

import authConfig from './auth.config';
import { NextResponse } from 'next/server';
// todos:
// move callbacks, sessions from '.auth.ts' to 'auth.config.ts'
// auth.ts will include only types, jwt strategy and mongoDB adapter.

const { auth } = NextAuth(authConfig);

//import { auth } from './auth';

export default auth((req) => {
  const isLoggedIn = !!req.auth;
  const { nextUrl } = req;

  console.log('route: ', nextUrl.pathname);
  //console.log('headers, ', req.headers);
  //console.log('COOKIES ', req.cookies);
  const callback = nextUrl.searchParams.get('callbackUrl');
  // console.log('LOGGED: ', isLoggedIn);

  const host = req.headers.get('host') || '';
  const subdomain = host.split('.')[0]; // Extract subdomain
  const url = req.nextUrl.clone();

  if (nextUrl.pathname.startsWith('/api/auth/')) {
    return;
  }
  if (subdomain && subdomain !== 'localhost:3000') {
    console.log(subdomain);
    // Append subdomain to the pathname to match app/[domain]
    url.pathname = `/${subdomain}${url.pathname}`;

    return NextResponse.rewrite(url);
  }

  return;
});

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

.env:

AUTH_REDIRECT_PROXY_URL=http://localhost:3000/api/auth
AUTH_SECRET=some_secret
AUTH_TRUST_HOST=true

AUTH_GOOGLE_ID=google_id
AUTH_GOOGLE_SECRET=google_secret

GITHUB_SECRET=git_secret
GITHUB_ID=git_id

How to reproduce

  1. git clone https://github.com/Dragosp33/aws-auth-test/tree/main
  2. set up env variables: AUTH_GOOGLE_ID and AUTH_GOOGLE_SECRET
  3. set up hosts file on your machine to include a subdomain: 127.0.0.1 subdomain.localhost
  4. go to http://subdomain.localhost:3000/auth/login
  5. try login via google

Expected behavior

I thought that this will create a proxy where the user from a subdomain doesn't really interact with the main domain's interface, instead, nextauth will handle this server side and redirect back to the subdomain to check for the state and pcke cookies. Or at least, send those cookies together to main domain.

@Dragosp33 Dragosp33 added bug Something isn't working triage Unseen or unconfirmed by a maintainer yet. Provide extra information in the meantime. labels Nov 12, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working triage Unseen or unconfirmed by a maintainer yet. Provide extra information in the meantime.
Projects
None yet
Development

No branches or pull requests

1 participant