amplify-backend icon indicating copy to clipboard operation
amplify-backend copied to clipboard

Support for custom domain on Auth resource

Open amalhub opened this issue 11 months ago • 16 comments

Environment information

System:
  OS: Windows 10 10.0.19045
  CPU: (16) x64 Intel(R) Core(TM) i7-10875H CPU @ 2.30GHz
  Memory: 13.03 GB / 31.77 GB
Binaries:
  Node: 20.15.1 - C:\Program Files\nodejs\node.EXE       
  Yarn: undefined - undefined
  npm: 10.3.0 - C:\Program Files\nodejs\npm.CMD
  pnpm: 9.5.0 - ~\AppData\Roaming\npm\pnpm.CMD
NPM Packages:
  @aws-amplify/auth-construct: 1.3.0
  @aws-amplify/backend: 1.2.0
  @aws-amplify/backend-auth: 1.1.3
  @aws-amplify/backend-cli: 1.2.5
  @aws-amplify/backend-data: 1.1.3
  @aws-amplify/backend-deployer: 1.1.0
  @aws-amplify/backend-function: 1.3.4
  @aws-amplify/backend-output-schemas: 1.2.0
  @aws-amplify/backend-output-storage: 1.1.1
  @aws-amplify/backend-secret: 1.1.0
  @aws-amplify/backend-storage: 1.1.2
  @aws-amplify/cli-core: 1.1.2
  @aws-amplify/client-config: 1.3.0
  @aws-amplify/deployed-backend-client: 1.4.0
  @aws-amplify/form-generator: 1.0.1
  @aws-amplify/model-generator: 1.0.5
  @aws-amplify/platform-core: 1.0.7
  @aws-amplify/plugin-types: 1.2.1
  @aws-amplify/sandbox: 1.2.0
  @aws-amplify/schema-generator: 1.2.1
  aws-amplify: 6.5.4
  aws-cdk: 2.155.0
  aws-cdk-lib: 2.155.0
  typescript: 5.5.4
AWS environment variables:
  AWS_NODEJS_CONNECTION_REUSE_ENABLED = 1
  AWS_SDK_LOAD_CONFIG = 1
  AWS_STS_REGIONAL_ENDPOINTS = regional
No CDK environment variables

Describe the bug

I have an Amplify Gen 2 NextJS app configured with an external Google OAuth provider. After purchasing a custom domain for my website externally, I successfully configured the app with the custom domain so that when I go to my custom domain from my browser the website homepage loads successfully.

Now, when I log in using Google OAuth, I am redirected to the OAuth consent screen, but it still shows the redirect URL as <userpool>.auth.<region>.amazoncognito.com. To change this I followed the below steps:

Steps:
Set Up Your Custom Domain in AWS Cognito:

Go to the Cognito Console and select your User Pool.
Under the App Integration section, choose Domain name.
Click Use your own domain and enter your custom domain (e.g., auth.yourdomain.com).
Set Up the DNS Record:

In your DNS management console (e.g., Route 53), create a CNAME record.
Point your custom domain (e.g., auth.yourdomain.com) to the AWS Cognito service domain (e.g., your-userpool-id.auth.region.amazoncognito.com).
Verify Your Domain:

Once the DNS changes propagate, Cognito will verify the domain. This can take up to 24 hours.
Update Your Google OAuth Configuration:

Log in to the Google Cloud Console.
Go to APIs & Services > Credentials.
Edit your OAuth 2.0 Client ID and update the Authorized redirect URIs to use your custom domain. 

Still it doesn't change the redirect URL because the auto generated amplify_outputs.json still has the amazon default domain <userpool>.auth.<region>.amazoncognito.com. I even tried redeploying the app, still it doesn't pick up the custom domain I configured in the userpool.

I there a way to configure this in the Amplify Gen 2 NextJS backend auth configuration? Or is this a bug?

Reproduction steps

Steps to reproduce given above.

amalhub avatar Dec 18 '24 14:12 amalhub

Hey @amalhub, thank you for reaching out. Adding custom domains isnt quite yet supported on defineAuth. Marking this as feature request. Additionally, manual changes on the console will not reflect when using CDK to deploy resources. but you should be able to extend the auth resource on the backend.ts using cdk constructs

import {
  Certificate,
  CertificateValidation,
} from "aws-cdk-lib/aws-certificatemanager"
import { HostedZone } from "aws-cdk-lib/aws-route53"

  // create a stack for domain resources
  const stack = backend.createStack("Domain")

  // if you're not creating additional DNS records you can just use `fromHostedZoneId()`
  const hostedZone = HostedZone.fromHostedZoneAttributes(stack, "HostedZone", {
    hostedZoneId: <HOSTED_ZONE_ID>,
    zoneName: <HOSTED_ZONE_NAME>,
  })


// create certificate
  const certificate = new Certificate(stack, "Certificate", {
    <DOMAIN_NAME>,
    validation: CertificateValidation.fromDns(hostedZone),
  })

  //  add the custom domain which should populate the amplify_outputs.json
  backend.auth.resources.userPool.addDomain("CustomDomain", {
    customDomain: {
      domainName,
      certificate,
    },
  })
}

ykethan avatar Dec 19 '24 19:12 ykethan

Hi @ykethan,

Thank you for your response and for suggesting an alternative. I will give it a try and reach out if I encounter any further issues.

It's a bit odd to see that this critical feature is missing in AWS Amplify Gen 2. Unusual that I'm the first to request such a feature, as it is a common requirement when deploying a web application to production with federated auth. It almost feels like I am among the first users to go live with a federated login in AWS Amplify.

amalhub avatar Jan 04 '25 07:01 amalhub

Having the same issue.

After extending the auth resource on the backend.ts using cdk constructs as explained by @ykethan, how do you get Google OAuth to use the custom cognito user pool domain instead of the default Cognito domain?

TobyMessier avatar Jan 04 '25 20:01 TobyMessier

@amalhub have your found a workaround for this?

TobyMessier avatar Jan 09 '25 16:01 TobyMessier

Hi @TobyMessier, I'm yet to try the suggested alternative solution because I submitted my OAuth consent screen for Google review to enable the App logo (hoping that it would hide the ugly AWS cognito URL) and I'm still waiting until the process is complete to try any alternatives.

However to answer your question; how do you get Google OAuth to use the custom cognito user pool domain instead of the default Cognito domain?, I believe you need to update your custom domain URL as one of the Authorized Redirect URLs in the Google OAuth client web application settings. Let me know if you get this to work.

amalhub avatar Jan 10 '25 11:01 amalhub

hey @ykethan, extending the auth resource on the backend.ts using cdk constructs as you recommended works to create a Custom domain, but when using the CDK to deploy resources, it automatically reverts back to the Cognito domain. This means users are still asked if they want to continue to the Cognito domain (very confusing for them) rather than the Custom domain.

Basically, this does not populate the amplify_outputs.json:

backend.auth.resources.userPool.addDomain("CustomDomain", { customDomain: { domainName, certificate, }, })

Any suggested workarounds for this?

TobyMessier avatar Feb 03 '25 05:02 TobyMessier

It appears to me that one underlying issue is here, where the custom resource that pulls in the domain information incorrectly handles custom domains.

    // domain
    const oauthDomain = userPool.CustomDomain ?? userPool.Domain ?? '';
    const fullDomainPath = `${oauthDomain}.auth.${region}.amazoncognito.com`;

The issue is that a CustomDomain should not be treated as a subdomain under amazoncognito.com. Instead, I believe the above code should be changed to:

const fullDomainPath = userPool.CustomDomain ?? `${userPool.Domain}.auth.${region}.amazoncognito.com`

I have also verified this locally by patching the @aws-amplify/backend-auth package and now see the expected custom domain output in amplify_outputs.json.

Edit: If you do test this on an existing stack, note that the way the lambda custom resource runs it will only update its output if the custom resource is recreated.

mpetito avatar Mar 07 '25 19:03 mpetito

I believe this works in the frontend UI, im using it in main.tsx

const fullAmplifyConfig: any = {
  ...amplifyConfig,
  Auth: {
    ...(amplifyConfig.Auth as any),
    Cognito: {
      ...((amplifyConfig.Auth as any).Cognito || {}),
      loginWith: {
        ...((amplifyConfig.Auth as any).Cognito.loginWith || {}),
        oauth: {
          ...((amplifyConfig.Auth as any).Cognito.loginWith.oauth || {}),
          domain: "auth.example.com"
        }
      }
    }
  },

but I just ran into some other issues because of it

lets-getitnow avatar May 22 '25 00:05 lets-getitnow

Hey @amalhub @TobyMessier did you guys find a solution?

rrodrigu3z avatar May 23 '25 19:05 rrodrigu3z

With all due respect, this is a rather unpleasant discovery.

I am sorry, but how can such a basic feature (the absence of which will obviously make the users of my app wondering whether it is a fishing website they're entering) not be present in something that positions itself as a 'production-ready' system with 'everything you need to build web and mobile apps'?

I apologize to all the devs here; I respect you all. I understand that the marketing and ads isn't a developer's job, but this honestly seems like I was scammed when decided to switch from Firebase.

Can we get an update on this, please?

uandere avatar Jul 26 '25 16:07 uandere

I spent hours on this issue today and I’m really disappointed. Hard to believe this isn’t a supported feature. The default domain alone is enough to scare people away.

NewCai avatar Aug 17 '25 00:08 NewCai

Anyone find a solution to this? I’ve tried mostly all the suggestions here and cannot get it to work with my React Amplify Gen2 app for Google Login. The default Cognito domain is getting utilized after user clicks login button.

smartsteedllc avatar Oct 03 '25 04:10 smartsteedllc

Can we get this feature request prioritized? As @amalhub and @uandere mentioned above, this is a fundamental feature.

The goal of using external id provider (e.g. Google) is to increase customer's trust on my app. If we end up showing a cryptic domain in the Google login screen, that trust will likely go away.

mengcao avatar Nov 02 '25 13:11 mengcao

any update or workarounds

hasadata avatar Nov 10 '25 02:11 hasadata

Looks like https://github.com/aws-amplify/amplify-backend/pull/3024 made the custom domain work for using existing Cognito resources (reference_auth). But it doesn't apply to Cognito resources directly created as part of the Amplify backend stack.

mengcao avatar Nov 23 '25 14:11 mengcao

I submitted https://github.com/aws-amplify/amplify-backend/pull/3056 as a stop-gap solution.

This PR allows Amplify app developer to specify a custom domain prefix in defineAuth. So instead of a cryptic url such as db049484d0476df65368.auth.us-east-1.amazoncognito.com, you can have something like <your-app-name>.auth.us-east-1.amazoncognito.com. You just need to do the following in your defineAuth code,

export const auth = defineAuth({
  loginWith: {
    ...
    externalProviders: {
      ...
      domainPrefix: '<your-app-name>',
    },
  },

It is not as good as a completely custom domain (what this issue is requesting), but I think it is better than the status quo.

mengcao avatar Nov 23 '25 22:11 mengcao