aws-amplify / amplify-js

A declarative JavaScript library for application development using cloud services.
https://docs.amplify.aws/lib/q/platform/js
Apache License 2.0
9.43k stars 2.13k forks source link

Redirect to url after clicking email verification link #612

Closed guanzo closed 6 years ago

guanzo commented 6 years ago

When the user clicks on the email verification link, they're taken to a confirmation page, located at

https://APP.auth.us-east-2.amazoncognito.com/confirmUser?client_id=CLIENT_ID&user_name=USERNAME&confirmation_code=CODE

I'd like the ability to specify a URL that the confirmation page will redirect to, thereby auto logging in the user. This will make the signup flow more streamlined. Perhaps there could be an extra parameter for the redirect url.

https://APP.auth.us-east-2.amazoncognito.com/confirmUser?client_id=CLIENT_ID&user_name=USERNAME&confirmation_code=CODE&redirect=URL

The way it works now is that after clicking the link, the user has to go back to my app and log in again, which is awkward.

nidsharm commented 6 years ago

Hi @guanzo ,

You can go to Cognito User Pool console for your pool, then on the left pane click on App Client Settings under App Integration. There is an option to set your Callback URL there. We don't currently support specifying the Cognito settings on awsmobile-cli. I'm adding this to our backlog. Let us know if you face any issues adding your url.

guanzo commented 6 years ago

@nidsharm That callback URL seems to be for cognito's hosted UI. I'm using my own UI.

yuntuowang commented 6 years ago

Hi @guanzo, yes, I understand your situation. It is a good point to add a parameter: https://APP.auth.us-east-2.amazoncognito.com/confirmUser?client_id=CLIENT_ID&user_name=USERNAME&confirmation_code=CODE&redirect=URL

I will mark this as a feature request. Thanks!

ChandruNextbrain commented 6 years ago

Hi @yuntuowang ,

Is that feature is implemented. Please respond asap. Thanks.

yuntuowang commented 6 years ago

Hi @ChandruNextbrain, this feature is not released yet. Thanks

lxmaran commented 6 years ago

Hello @yuntuowang , When do you expect to release this feature?

yuntuowang commented 6 years ago

Hi @lxmaran, at this point, we cannot comment on the release time.

Chitrarekha commented 6 years ago

Hi @guanzo @yuntuowang how to generate codeParameter values

I have the below link https://domainname.amazoncognito.com/confirmUser?client_id=clientid3&user_name=heavenly&confirmation_code=undefined

conformation code is undefined i used "&confirmation_code=" + event.request.codeParameter+ clivk here any help?

Chitrarekha commented 6 years ago

can anyone help me regarding how to customise the url link for email verification ?

Deliforce commented 6 years ago

That is auto generate by AWS. You can't customize as of now.

Chitrarekha commented 6 years ago

Hi @Deliforce , is there any option to how to achieve email verification ? i have to verify email and phoneno both. CustomMessage_SignUp triggerSource is not sending mail to verify, could you please help me .

Deliforce commented 6 years ago

In Cognito, After creating user pool go to MFA & Verification section. There you have option to set Email & Phone number verification.

huihe commented 6 years ago

Hi @yuntuowang, is there any update about redirect after confirmUser?

guanzo commented 6 years ago

I managed to implement the redirect myself with the help of this SO post: https://stackoverflow.com/questions/47159568/how-to-redirect-after-confirm-amazon-cognito-using-confirmation-url

In Cognito's "Message Customizations" tab, under the option "Do you want to customize your email verification messages?", select "Code".

Create a cognito trigger for "Custom message". Here's my lamba code:

exports.handler = (event, context, callback) => {
    // Identify why was this function invoked
    if(event.triggerSource === "CustomMessage_SignUp") {
        // Ensure that your message contains event.request.codeParameter. This is the placeholder for code that will be sent
        const { codeParameter } = event.request
        const { userName, region } = event
        const { clientId } = event.callerContext
        const { email } = event.request.userAttributes
        const url = 'https://example.com/api/confirmSignup'
        const link = `<a href="${url}?code=${codeParameter}&username=${userName}&clientId=${clientId}&region=${region}&email=${email}" target="_blank">here</a>`
        event.response.emailSubject = "Your verification link"; // event.request.codeParameter
        event.response.emailMessage = `Thank you for signing up. Click ${link} to verify your email.`;
    }

    // Return to Amazon Cognito
    callback(null, event);
};

More information about what kind of data is available to the function: https://docs.aws.amazon.com/cognito/latest/developerguide/user-pool-lambda-custom-message.html?shortFooter=true

The link directs the user to a server that you control. The server then sends a POST request to the Cognito API endpoint which verifies the users email. Check the SO post for what that request looks like.

Since you now control the request, redirect the user wherever you like.

Hopefully AWS implements this feature soon, because this is an annoying workaround for such a simple feature.

bmoquist commented 6 years ago

Hi @yuntuowang - is there any update on this? This is a basic feature for so many applications and significantly improves the user experience. Furthermore, it has been a feature request from your customers for a long time (the above SO article is from Nov. 2017).

bmoquist commented 6 years ago

@guanzo - Your solution worked brilliantly!

Create the Lambda function above. Then, in the Cognito User Pool UI, set the Message Customization trigger to that function under the Triggers section and set the verification type to code in Message Customizations section.

Here is the second half needed on the server (Node here) using the AWS SDK for everyone's reference:

'use strict';
var AWS = require('aws-sdk');
AWS.config.setPromisesDependency(require('bluebird'));
var CognitoIdentityServiceProvider = new AWS.CognitoIdentityServiceProvider({ apiVersion: '2016-04-19', region: process.env.COGNITO_AWS_REGION });

exports.verifyEmailAddress = function(req, res, next) {

  const confirmationCode = req.query.code
  const username = req.query.username
  const clientId = req.query.clientId
  const region = req.query.region
  const email = req.query.email

  let params = {
    ClientId: clientId,
    ConfirmationCode: confirmationCode,
    Username: username
  }

  var confirmSignUp = CognitoIdentityServiceProvider.confirmSignUp(params).promise()

  confirmSignUp.then(
    (data) => {
      let redirectUrl = process.env.POST_REGISTRATION_VERIFICATION_REDIRECT_URL
      res.redirect(redirectUrl);
    }
  ).catch(
    (error) => {
      next(error)
    }
  )
}
holtc commented 5 years ago

Why was this closed? As far as I can tell, it still has not been implemented

lexicalparadoxx commented 5 years ago

I tried to reproduce this workaround, but cognito post sign up still sends the default content from the Message Customization panel.

I also have a custom message function here for ForgotPassword, does it affect the triggering for the SignUp? It shouldn't be experienced cause of the condition for the event.triggerSource, right?

Really weird that it doesn't got triggered.

cliffordh commented 5 years ago

Does this solution require the user to login again? I would prefer that once the user creates their account, clicks the email link, that they are "signed in" and can then use the app. To require them to enter their credentials again seems like a bad UX.

cliffordh commented 5 years ago

@bmoquist In your second half example, is your code a Lambda? If so, what trigger is it associated with?

bmoquist commented 5 years ago

No, the code is an API controller in Node Express. The Lambda function written by guanzo sends an email with the API url. The user clicks on the link in the email and is redirected to the API (my code above). The server conducts verification on behalf of the user and redirects the user to a new url. You could apply the same logic of my code using Lambda as the API.

Yes, the user will be required to login again - it would be a better UX experience if they didn't need to.

cliffordh commented 5 years ago

This Lambda snippet (found on SO) auto confirms the user:

exports.handler = (event, context, callback) => {
    event.response.autoConfirmUser = true;
    //https://stackoverflow.com/questions/47361948/how-to-confirm-user-in-cognito-user-pools-without-verifying-email-or-phone
    //event.response.autoVerifyEmail = true;  // this is NOT needed if e-mail is not in attributeList
    //event.response.autoVerifyPhone = true;  // this is NOT needed if phone # is not in attributeList
    context.done(null, event);
};

Could we combine these two approaches, auto-confirm the user which lets them use the app without requiring a new login, but then also trigger email verification? Accounts which are not verified would have limited access and/or delete after a period of time.

bush commented 5 years ago

Has there been any movement on this? It looks like cognito really needs the extra redirect parameter ... I really think this should be re-opened. If its not going to be reopened it would be nice to confirm there is an actual feature request in the backlog.

justinbrush702 commented 5 years ago

Whether you add a redirect parameter to the AmazonCognitoIdentity.CognitoUserPool or just let us add a custom url in the Cognito user pool UI, this feature should be added ASAP!

elorzafe commented 5 years ago

@bush @justinbrush702 there is a RFC on this issue, we are discussing auth enhancements there.

bush commented 5 years ago

@elorzafe thanks for the update! Appreciate the feedback.

RamyaChinnadurai commented 5 years ago

Is this feature implemented? Please, someone, give a reply.

akalana commented 5 years ago

I am also face this issue ?Is there any updates?

BrentLoft1 commented 5 years ago

Timeline for when this feature will be implemented?

joshuabalduff commented 5 years ago

Please add this as a priority of possible really kind of annoying doing workarounds @yuntuowang I'll throw you an extra $20 to expedite this lol

davmrs commented 5 years ago

Yes, we need the same feature. I think it's a must for this product.

olivierto commented 5 years ago

it's so annoying to use workaround with lambda for this... +1

uncle-scooter commented 5 years ago

There should be little to no lock-in for delivery of codes. If I was able to have more control of the delivery mechanisms then we wouldn't have to be writing our own work-arounds.

Would be much better if Cognito/Amplify let us drop in our own delivery method and modifications and not just stuck to SES and SNS without access to the params.

DanielWFrancis commented 5 years ago

this should be extremely simple, curious to know what the holdup is for a redirect param?

MarcelBlockchain commented 5 years ago

thanks for posting the snippets!

marcinkaczor commented 5 years ago

We also need the same feature.

rchristiemtt commented 5 years ago

Why has this been closed? We too need this feature

mlabieniec commented 5 years ago

@rchristiemtt i believe this feature was launched with the cli's release with trigger support recently: https://aws-amplify.github.io/docs/cli-toolchain/cognito-triggers

kelvinliang-seekers commented 5 years ago

We need this features as well lol

jacobjoy24 commented 5 years ago

I have written a complete guide for the re-direct functionality,

https://medium.com/@jacobjoyseba/redirect-user-using-amazon-cognito-confirmation-url-d8ccb11bac75

davekiss commented 4 years ago

Here's a bit cleaner version of the confirm step for anyone using Lambda proxy integration instead / HTTP APIs instead of the API Gateway. Make sure your lambda has permission to confirm users in Cognito.

const AWS = require("aws-sdk");
const cognito = new AWS.CognitoIdentityServiceProvider();
const REDIRECT_URL = process.env.POST_REGISTRATION_VERIFICATION_REDIRECT_URL;

exports.handler = async event => {
  const { code, username, clientId } = event.queryStringParameters;

  const params = {
    ClientId: clientId,
    ConfirmationCode: code,
    Username: username
  };

  try {
    await cognito.confirmSignUp(params).promise();
    return {
      statusCode: 302,
      headers: {
        Location: REDIRECT_URL
      }
    };
  } catch (error) {
    return { statusCode: 400, body: error.message };
  }
};
lebnic commented 4 years ago

Cognito should at least update the doc / interface... The link simply "does not work out of the box..." contrary to what is "advertised" :

Capture d’écran, le 2020-04-10 à 16 29 11
DanielWFrancis commented 4 years ago

Adding to the long list of people who want to see this. Seems exceptionally simple to implement.

stevelizcano commented 4 years ago

This is extremely frustrating and makes working with amplify/cognito a negative experience.

SilverLinings89 commented 4 years ago

This functionality as a UI element in the AWS console would be very helpful. A simple URL to redirect to if the confirmation was successful would be exactly what people in most usecases want I guess. Weird that such a core functionality would require quirky workarounds as have been mentioned above - this is after all a situation something like half of all registered users should go through (I guess 50% code, 50% link)

bibek-magar commented 4 years ago

Can some one help me with these.. I have been stuck in this work around .....

asterikx commented 4 years ago

From what I understand we need to do two things

  1. Customize the confirmation link sent to the user (to point to sth. we have control of to redirect the user after confirmation)
  2. Call the Cognito API to confirm the user (based on the information in the confirmation link) and redirect the user to where we want to

For the first step, we need to create a Custom Message Lambda Trigger since Cognito's static message customization does not allow us to encode redirect information in the generated confirmation link.

For the second step, the suggested solution uses a custom API endpoint with a Lambda to call the Cognito API (to confirm the user) and returns an HTTP 302 to redirect the user based on the redirect information encoded in the confirmation link.

I wonder why no one handles confirmation and redirection on the client-side?

I case of a SPA (e.g. React), I could have the following route for confirmation: /confirm?username=${username}&code=${code}

React Router v6

<Routes>
  <Route path="/confirm" element={<Confirm />} />
</Routes>

The Confirm component parses the search parameters, confirms the user using the Amplify's confirmSingUp method (calling the Cognito API under the hood), and, on success, replaces the current location with the previous location (or a default one).

import { useEffect } from 'react';
import { useLocation, useNavigate } from 'react-router-dom';
import { Auth } from 'aws-amplify'; // pre-configured with clienId

export function Confirm() {
  const navigate = useNavigate();
  const location = useLocation();
  const search = new URLSearchParams(location.search);

  const username = search.get('username') || '';
  const code = search.get('code') || '';

  useEffect(() => {
    const confirmUser = async () => {
      try {
        await Auth.confirmSignUp(username, code);

        const prevPath = (location.state as { from: string }).from || '/home';
        navigate(prevPath, { replace: true });
      } catch (err) {
        // handle error
      }
    };
    confirmUser();
  }, [username, code]);

  return null;
}

I haven't tested this solution yet, but I think it should work ...

I believe it is more flexible than using a custom API route/lambda with a fixed redirect URL. It can redirect the user to the previous location (which is useful for when confirmation must not happen immediately after sign up) and simplifies error handling on the client (expired links etc.).

I'm wondering if there are (major) drawbacks of such an implementation compared to a server-side solution? At the end of the day, both Lambda and Amplify make calls to the Cognito API, while Amplify adds useful methods for these calls.

harleyguru commented 4 years ago

@asterikx I think it's impossible to do this on FE as the users would get the verification email through email (not in-app). That's the reason why we should expose the endpoint for verification on server side.

asterikx commented 4 years ago

I have it working now, using only FE. However, as the link in the verification email will open a new tab in the user's default browser (possibly on another device), redirection based on (in-memory) FE state will not work indeed.

ramanaditya commented 4 years ago

It is better to have the authentication process working in the backend, due to following reasons

I have done this through the backend referring the links posted above, but this should not be the actual solution, for a single process we have to make multiple requests. This should one of the feature updates if the team is planning upon.

This should be more like the federated login where the tab automatically gets closed upon authentication.

Looking forward to seeing the update ASAP.