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

Nextjs middleware and social Google login #13056

Closed
3 tasks done
Maayanyeru123 opened this issue Feb 27, 2024 · 14 comments
Closed
3 tasks done

Nextjs middleware and social Google login #13056

Maayanyeru123 opened this issue Feb 27, 2024 · 14 comments
Assignees
Labels
Auth Related to Auth components/category Next.js question General question

Comments

@Maayanyeru123
Copy link

Maayanyeru123 commented Feb 27, 2024

Before opening, please confirm:

JavaScript Framework

React

Amplify APIs

Authentication, GraphQL API, Storage

Amplify Version

v6

Amplify Categories

auth

Backend

Amplify CLI

Environment information

 System:
    OS: Windows 11 10.0.22631
    CPU: (8) x64 11th Gen Intel(R) Core(TM) i7-1185G7 @ 3.00GHz
    Memory: 21.57 GB / 31.71 GB
  Binaries:
    Node: 20.3.0 - C:\Program Files\nodejs\node.EXE
    Yarn: 1.22.21 - ~\AppData\Roaming\npm\yarn.CMD
    npm: 9.6.7 - C:\Program Files\nodejs\npm.CMD
  Browsers:
    Edge: Chromium (122.0.2365.52)
    Internet Explorer: 11.0.22621.1
  npmPackages:
    @ampproject/toolbox-optimizer:  undefined ()
    @aws-amplify/adapter-nextjs: ^1.0.16 => 1.0.16
    @aws-amplify/adapter-nextjs/api:  undefined ()
    @aws-amplify/adapter-nextjs/data:  undefined ()
    @babel/core:  undefined ()
    @babel/runtime:  7.22.5
    @edge-runtime/cookies:  4.0.2
    @edge-runtime/ponyfill:  2.4.1
    @edge-runtime/primitives:  4.0.2
    @hapi/accept:  undefined ()
    @headlessui/react: ^1.7.18 => 1.7.18
    @mswjs/interceptors:  undefined ()
    @napi-rs/triples:  undefined ()
    @next/font:  undefined ()
    @next/react-dev-overlay:  undefined ()
    @opentelemetry/api:  undefined ()
    @reduxjs/toolkit: ^2.2.1 => 2.2.1
    @reduxjs/toolkit-query:  1.0.0
    @reduxjs/toolkit-query-react:  1.0.0
    @reduxjs/toolkit-react:  1.0.0
    @types/node: ^20 => 20.11.16
    @types/react: ^18 => 18.2.55
    @types/react-dom: ^18 => 18.2.18
    @vercel/nft:  undefined ()
    @vercel/og:  0.6.2
    acorn:  undefined ()
    amphtml-validator:  undefined ()
    anser:  undefined ()
    arg:  undefined ()
    assert:  undefined ()
    async-retry:  undefined ()
    async-sema:  undefined ()
    autoprefixer: ^10.4.17 => 10.4.17
    aws-amplify: ^6.0.15 => 6.0.15
    aws-amplify/adapter-core:  undefined ()
    aws-amplify/analytics:  undefined ()
    aws-amplify/analytics/kinesis:  undefined ()
    aws-amplify/analytics/kinesis-firehose:  undefined ()
    aws-amplify/analytics/personalize:  undefined ()
    aws-amplify/analytics/pinpoint:  undefined ()
    aws-amplify/api:  undefined ()
    aws-amplify/api/server:  undefined ()
    aws-amplify/auth:  undefined ()
    aws-amplify/auth/cognito:  undefined ()
    aws-amplify/auth/cognito/server:  undefined ()
    aws-amplify/auth/enable-oauth-listener:  undefined ()
    aws-amplify/auth/server:  undefined ()
    aws-amplify/datastore:  undefined ()
    aws-amplify/in-app-messaging:  undefined ()
    aws-amplify/in-app-messaging/pinpoint:  undefined ()
    aws-amplify/push-notifications:  undefined ()
    aws-amplify/push-notifications/pinpoint:  undefined ()
    aws-amplify/storage:  undefined ()
    aws-amplify/storage/s3:  undefined ()
    aws-amplify/storage/s3/server:  undefined ()
    aws-amplify/storage/server:  undefined ()
    aws-amplify/utils:  undefined ()
    babel-packages:  undefined ()
    browserify-zlib:  undefined ()
    browserslist:  undefined ()
    buffer:  undefined ()
    bytes:  undefined ()
    ci-info:  undefined ()
    cli-select:  undefined ()
    client-only:  0.0.1
    comment-json:  undefined ()
    compression:  undefined ()
    conf:  undefined ()
    constants-browserify:  undefined ()
    content-disposition:  undefined ()
    content-type:  undefined ()
    cookie:  undefined ()
    cross-spawn:  undefined ()
    crypto-browserify:  undefined ()
    css.escape:  undefined ()
    data-uri-to-buffer:  undefined ()
    debug:  undefined ()
    devalue:  undefined ()
    domain-browser:  undefined ()
    edge-runtime:  undefined ()
    eslint: ^8 => 8.56.0
    eslint-config-next: 14.1.0 => 14.1.0
    events:  undefined ()
    find-cache-dir:  undefined ()
    find-up:  undefined ()
    framer-motion: ^11.0.5 => 11.0.6
    fresh:  undefined ()
    get-orientation:  undefined ()
    glob:  undefined ()
    gzip-size:  undefined ()
    http-proxy:  undefined ()
    http-proxy-agent:  undefined ()
    https-browserify:  undefined ()
    https-proxy-agent:  undefined ()
    icss-utils:  undefined ()
    ignore-loader:  undefined ()
    image-size:  undefined ()
    is-animated:  undefined ()
    is-docker:  undefined ()
    is-wsl:  undefined ()
    jest-worker:  undefined ()
    json5:  undefined ()
    jsonwebtoken:  undefined ()
    loader-runner:  undefined ()
    loader-utils:  undefined ()
    lodash.curry:  undefined ()
    lru-cache:  undefined ()
    micromatch:  undefined ()
    mini-css-extract-plugin:  undefined ()
    nanoid:  undefined ()
    native-url:  undefined ()
    neo-async:  undefined ()
    next: 14.1.0 => 14.1.0
    next-auth: ^5.0.0-beta.9 => 5.0.0-beta.11
    node-fetch:  undefined ()
    node-html-parser:  undefined ()
    ora:  undefined ()
    os-browserify:  undefined ()
    p-limit:  undefined ()
    path-browserify:  undefined ()
    platform:  undefined ()
    postcss: ^8.4.35 => 8.4.35 (8.4.31)
    postcss-flexbugs-fixes:  undefined ()
    postcss-modules-extract-imports:  undefined ()
    postcss-modules-local-by-default:  undefined ()
    postcss-modules-scope:  undefined ()
    postcss-modules-values:  undefined ()
    postcss-preset-env:  undefined ()
    postcss-safe-parser:  undefined ()
    postcss-scss:  undefined ()
    postcss-value-parser:  undefined ()
    process:  undefined ()
    punycode:  undefined ()
    querystring-es3:  undefined ()
    raw-body:  undefined ()
    react: ^18 => 18.2.0
    react-builtin:  undefined ()
    react-dom: ^18 => 18.2.0
    react-dom-builtin:  undefined ()
    react-dom-experimental-builtin:  undefined ()
    react-experimental-builtin:  undefined ()
    react-is:  18.2.0
    react-redux: ^9.1.0 => 9.1.0
    react-refresh:  0.12.0
    react-router-dom: ^6.22.1 => 6.22.1
    react-server-dom-turbopack-builtin:  undefined ()
    react-server-dom-turbopack-experimental-builtin:  undefined ()
    react-server-dom-webpack-builtin:  undefined ()
    react-server-dom-webpack-experimental-builtin:  undefined ()
    regenerator-runtime:  0.13.4
    sass-loader:  undefined ()
    scheduler-builtin:  undefined ()
    scheduler-experimental-builtin:  undefined ()
    schema-utils:  undefined ()
    semver:  undefined ()
    send:  undefined ()
    server-only:  0.0.1
    setimmediate:  undefined ()
    shell-quote:  undefined ()
    source-map:  undefined ()
    stacktrace-parser:  undefined ()
    stream-browserify:  undefined ()
    stream-http:  undefined ()
    string-hash:  undefined ()
    string_decoder:  undefined ()
    strip-ansi:  undefined ()
    superstruct:  undefined ()
    tailwindcss: ^3.4.1 => 3.4.1
    tar:  undefined ()
    terser:  undefined ()
    text-table:  undefined ()
    timers-browserify:  undefined ()
    tty-browserify:  undefined ()
    typescript: ^5 => 5.3.3
    ua-parser-js:  undefined ()
    unistore:  undefined ()
    util:  undefined ()
    vm-browserify:  undefined ()
    watchpack:  undefined ()
    web-vitals:  undefined ()
    webpack:  undefined ()
    webpack-sources:  undefined ()
    ws:  undefined ()
    zod:  undefined ()
  npmGlobalPackages:
    @aws-amplify/cli: 12.10.1
    aws-amplify: 6.0.16
    aws-sam-local: 0.2.11
    latest: 0.2.0
    nodemon: 3.0.3
    npx: 10.2.2
    ts-node: 10.9.2
    typescript: 5.3.3
    yarn: 1.22.21

Describe the bug

When using NextJs middleware as stated in Amplify documentation after signing in with Google provider "await fetchAuthSession"
Doesn't return the signing user

Expected behavior

Getting the signing user session

Reproduction steps

1, going to app Home page
2. login with Google account
3. Going to Home
4. returns to sign in as user is not authenticated

Code Snippet

aws-exports.js

{
  "aws_project_region": "eu-west-1",
  "aws_cognito_identity_pool_id": XXXX
  "aws_cognito_region": "eu-west-1",
  "aws_user_pools_id": XXXX,
  "aws_user_pools_web_client_id": XXXXX,
  "oauth": {
    "domain": XXXXX,
    "scope": [
      "phone",
      "email",
      "openid",
      "profile",
      "aws.cognito.signin.user.admin"
    ],
    "redirectSignIn": "http://localhost:3000/home",
    "redirectSignOut": "http://localhost:3000/login/signin",
    "responseType": "code"
  },
  "federationTarget": "COGNITO_USER_POOLS",
  "aws_cognito_username_attributes": [],
  "aws_cognito_social_providers": [
    "GOOGLE"
  ],
  "aws_cognito_signup_attributes": [
    "EMAIL"
  ],
  "aws_cognito_mfa_configuration": "OFF",
  "aws_cognito_mfa_types": [
    "SMS"
  ],
  "aws_cognito_password_protection_settings": {
    "passwordPolicyMinLength": 8,
    "passwordPolicyCharacters": []
  },
  "aws_cognito_verification_mechanisms": [
    "EMAIL"
  ]
}

serverUtils.ts

import { createServerRunner } from '@aws-amplify/adapter-nextjs';
import config from '../../amplifyconfiguration.json';

export const { runWithAmplifyServerContext } = createServerRunner({
  config
});

layout.tsx

import config from './aws-exports.js';
Amplify.configure(config, {
  ssr: true, 
});

middleware.ts

import { fetchAuthSession } from 'aws-amplify/auth/server';
import { NextRequest, NextResponse } from 'next/server';
import { runWithAmplifyServerContext } from '@/app/utils/server/serverUtils';
const authRoutes =['home'];
export async function middleware(request: NextRequest) {
  const response = NextResponse.next();
  const authenticated = await runWithAmplifyServerContext({
    nextServerContext: { request, response },
    operation: async (contextSpec:any) => {
      try {
        const session = await fetchAuthSession(contextSpec);
        return session.tokens !== undefined;
      } catch (error) {
        return false;
      }
    }
  });
  if (authenticated) {
    return NextResponse.next();
  }
  return NextResponse.redirect(new URL('/login/signin', request.url));
}

export const config = {
  matcher: [
    /*
     * Match all request paths except for the ones starting with:
     * - api (API routes)
     * - _next/static (static files)
     * - _next/image (image optimization files)
     * - favicon.ico (favicon file)
     */
    '/((?!api|_next/static|logo-white.svg|_next/image|logo.svg|login|signin|signup|login/signup/success|icons|img|public|$).*)',
 
  ]
};

import Image from "next/image";
import { signInWithRedirect } from "aws-amplify/auth";

interface SocialSignInButtonProps {
    provider: 'Google' | 'Facebook' | 'Apple'; // Add more providers as needed
    isLogin: boolean;
    // customState?: string; // Optional prop to pass custom state if needed
}

SocialLoginButton.tsx

const SocialSignInButton: React.FC<SocialSignInButtonProps> = ({ provider, isLogin }) => {
  const buttonText = !isLogin ? 'Sign up with' : '';
  const iconSize = isLogin ? 20 : 24; // Adjust icon size if needed
  const isEnabled = provider === 'Google';
  const buttonClass = `social-button ${provider.toLowerCase()} ${isLogin ? 'icon' : ''} ${!isEnabled ? 'disabled:bg-slate-400' : ''}`;

  const handleClick = () => {
    if (isEnabled) {
      signInWithRedirect({ provider, customState: 'Google' });
    }
  };

  return (
    <div>
      <button
        type="button"
        className={buttonClass}
        disabled={!isEnabled}
        onClick={handleClick}
      >
        <Image src={`/icons/${provider.toLowerCase()}.svg`} alt={`${provider} Logo`} width={iconSize} height={iconSize} priority />
        {!isLogin && ` ${buttonText} ${provider}`}
      </button>
    </div>
  );
};

export default SocialSignInButton;

Log output

// Put your logs below this line


aws-exports.js

/* eslint-disable */
// WARNING: DO NOT EDIT. This file is automatically generated by AWS Amplify. It will be overwritten.

const awsmobile = {
"aws_project_region": "eu-west-1",
"aws_cognito_identity_pool_id": "XXXX",
"aws_cognito_region": "eu-west-1",
"aws_user_pools_id": "XXXXX",
"aws_user_pools_web_client_id": "XXXXX",
"oauth": {
"domain": "XXXXXX",
"scope": [
"phone",
"email",
"openid",
"profile",
"aws.cognito.signin.user.admin"
],
"redirectSignIn": "http://localhost:3000/home",
"redirectSignOut": "http://localhost:3000/login/signin",
"responseType": "code"
},
"federationTarget": "COGNITO_USER_POOLS",
"aws_cognito_username_attributes": [],
"aws_cognito_social_providers": [
"GOOGLE"
],
"aws_cognito_signup_attributes": [
"EMAIL"
],
"aws_cognito_mfa_configuration": "OFF",
"aws_cognito_mfa_types": [
"SMS"
],
"aws_cognito_password_protection_settings": {
"passwordPolicyMinLength": 8,
"passwordPolicyCharacters": []
},
"aws_cognito_verification_mechanisms": [
"EMAIL"
]
};

export default awsmobile;

Manual configuration

No response

Additional configuration

No response

Mobile Device

No response

Mobile Operating System

No response

Mobile Browser

No response

Mobile Browser Version

No response

Additional information and screenshots

No response

@Maayanyeru123 Maayanyeru123 added the pending-triage Issue is pending triage label Feb 27, 2024
@hasadata
Copy link

+1
I am using amplify Authenticator UI and facing the same issues, the cookies are not set, the middleware is unable to retrieve the user

@cwomack cwomack added Auth Related to Auth components/category Next.js labels Feb 27, 2024
@cwomack cwomack self-assigned this Feb 27, 2024
@HuiSF
Copy link
Member

HuiSF commented Feb 27, 2024

Hi @Maayanyeru123 @hasadata thanks for opening this issue.

Looking at @Maayanyeru123 's configuration, I anticipate you are calling signInWithRedirect from the route /signin, after your end user sign in at Google's UI, it redirects your end user back to the route /home. If that's the case, you would need to follow this instruction to ensure the OAuth completion listener is added to your /home route so it can completes the sign in flow and persist the auth token in cookie store.

@hasadata
Copy link

adding the import fixed the issue

@cwomack
Copy link
Member

cwomack commented Feb 27, 2024

Thanks for the confirmation, @hasadata.

@Maayanyeru123, let us know if it resolves it for you as well.

@cwomack cwomack added question General question pending-response and removed pending-triage Issue is pending triage labels Feb 27, 2024
@Maayanyeru123
Copy link
Author

Thanks for the confirmation, @hasadata.

@Maayanyeru123, let us know if it resolves it for you as well.

Not for me :) probably something I am missing here.
The Home page is secured asset so implementing the import 'aws-amplify/auth/enable-oauth-listener'; will even work?

@Maayanyeru123
Copy link
Author

I fixed it with an ugly hack i created a middle page called redirect but this is so ugly

@cwomack
Copy link
Member

cwomack commented Feb 28, 2024

@Maayanyeru123, would you mind sharing the hacky way that you had to work around this? Wondering if we can provide any suggestions on it if you can share the frontend code. Thanks!

@Maayanyeru123
Copy link
Author

Maayanyeru123 commented Feb 29, 2024

@Maayanyeru123, would you mind sharing the hacky way that you had to work around this? Wondering if we can provide any suggestions on it if you can share the frontend code. Thanks!

Hey,
So I have created the following page redirect that is not protected by the middleware it imports aws-amplify/auth/enable-oauth-listener it is working perfectly fine but when i am putting it on the protected resource(Home Page) it doesn't work


"use client";
import 'aws-amplify/auth/enable-oauth-listener';
import { useRouter } from "next/navigation";

import { useAppSelector } from '@/app/redux/store';
import { useEffect } from 'react';
import { HOME} from '@/app/utils/client/consts';
import { getCurrentUser } from "aws-amplify/auth";
function Redirect() {

    const router = useRouter();
    const username = useAppSelector((state:any)=>state.AuthReducer.value.username);
    let currentUser;
    useEffect(() => {
        async function goToHome() {
            currentUser = await getCurrentUser();
            router.push(HOME);   
        }
        goToHome();
                
    }, []);
   
    return (
        <div>
            {currentUser}
        </div>
    );
  };
  export default Redirect;

The currentUser = await getCurrentUser(); returns the user correctly.

@AtharvArolkar
Copy link

Can you share please more on how did call the Redirect. Im facing the same issue. It'll be helpful to me

@jonaskinnvall
Copy link

Hi @Maayanyeru123 @hasadata thanks for opening this issue.

Looking at @Maayanyeru123 's configuration, I anticipate you are calling signInWithRedirect from the route /signin, after your end user sign in at Google's UI, it redirects your end user back to the route /home. If that's the case, you would need to follow this instruction to ensure the OAuth completion listener is added to your /home route so it can completes the sign in flow and persist the auth token in cookie store.

Hi I'm having a similar issue although I'm using next 14 BUT with the pages router and authenticating towards a custom provider.

The authentication works out fine but my middleware seems to run - and call fetchAuthSession (just like in the docs) - before the cookies have been stored, when loading e.g. "../overview?code=.." thus returning undefined tokens. If I then manually refresh the page e.g. "../overview" in the browser the tokens are returned correctly in the middleware.

I haven't been able to make it work when by importing import 'aws-amplify/auth/enable-oauth-listener'; but maybe I need to do something else when using the pages router?

Thanks in advance!

@github-actions github-actions bot added the pending-maintainer-response Issue is pending a response from the Amplify team. label Sep 27, 2024
@HuiSF
Copy link
Member

HuiSF commented Sep 27, 2024

Hi @jonaskinnvall the issue you are facing is somewhat a limitation of doing the final step of the OAuth sign in on the client side - exchanging auth tokens using the code. When the Hosted UI redirects back to the redirect URL you specified, before the auth tokens are exchanged, there is no valid user session, therefore if you are redirecting back to a protected route, the fetchAuthSession call in the middleware will return nothing.

Hence, my recommendation here is that the redirect URL should be an unprotected route, e.g. it can be the sign-in page again, in which you can add a Hub listener to listen to signedIn event, when it triggers, you can then navigate to another protected route that you prefer.

@github-actions github-actions bot removed the pending-maintainer-response Issue is pending a response from the Amplify team. label Sep 27, 2024
@jonaskinnvall
Copy link

Thanks for the quick answer - very good insight :) I solved it for the time being by redirecting to sign-in - as you also suggest - but instead render a kind of "go to application" button for the user to click which links to the protected route and then it of course works! But I'll try the Hub out to, which I've actually used like this previously, don't know why I didn't come to think of that now...

@github-actions github-actions bot added the pending-maintainer-response Issue is pending a response from the Amplify team. label Sep 27, 2024
@cwomack
Copy link
Member

cwomack commented Sep 27, 2024

@Maayanyeru123, wanted to check in and see if there's still a blocker here or if the workaround is still working for you. This comment above may also be helpful, but let us know if there's a need to keep this issue open or help further.

Thanks!

@cwomack cwomack added the pending-community-response Issue is pending a response from the author or community. label Sep 27, 2024
@github-actions github-actions bot removed the pending-maintainer-response Issue is pending a response from the Amplify team. label Sep 27, 2024
@cwomack
Copy link
Member

cwomack commented Oct 22, 2024

Closing this issue as we have not heard back from you. If you are still experiencing this, please feel free to reply back and provide any information previously requested and we'd be happy to re-open the issue.

Thank you!

@cwomack cwomack closed this as completed Oct 22, 2024
@github-actions github-actions bot removed the pending-community-response Issue is pending a response from the author or community. label Oct 22, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Auth Related to Auth components/category Next.js question General question
Projects
None yet
Development

No branches or pull requests

6 participants