29

I want to redirect to a specific url after the user confirmation in amazon cognito.

When a user sign up he will get confirmation mail with a verification link as follows https://<>.auth.us-west-2.amazoncognito.com/confirmUser?client_id=<<>>&user_name=<<>>&confirmation_code=<<>>

If the user clicks the above link it will redirect to confirmation page.

Once the user confirmation is completed the page should redirect to my application.

Please give me some idea to solve this problem.

Richardson. M
  • 852
  • 2
  • 17
  • 28

4 Answers4

25

Currently, this redirection can't be done using verification link in email. I tried adding redirect_uri to the verification URL a while back but they do not work.

Workaround

I know this is a convoluted workaround for such a simple requirement. The best way would be to raise a feature request and hope they support a redirect_uri in the Cognito URL.

EDIT

To save your lambda costs, you could also use an HTTP endpoint in your API and make a request to the cognito service endpoint for your region. Example:

POST  HTTP/1.1
Host: cognito-idp.us-east-1.amazonaws.com
x-amz-target: AWSCognitoIdentityProviderService.ConfirmSignUp
Content-Type: application/x-amz-json-1.1

{
  "ClientId":"xxxxxxxxxxxxx",
  "ConfirmationCode":"123456",
  "Username":"username"
}
agent420
  • 3,291
  • 20
  • 27
  • What are the placeholders to use for confirmation_code, client_id, user_name, etc in the URL : https://myapi.abc.com/confirm?client_id=somevalue&user_name=some_user&confirmation_code=some_code&redirect_uri=https://myapp.com - I am unable to locate it in the cognito documentation – vrtx54234 Nov 08 '17 at 04:09
  • 1
    You would need to set this message using a custom message lambda trigger. Confirmation code would be 'event.request.codeParameter', username in 'event.request.userAttributes'. Just log the 'event' object and see all the available values – agent420 Nov 08 '17 at 04:30
  • 1
    http://docs.aws.amazon.com/cognito/latest/developerguide/cognito-user-identity-pools-working-with-aws-lambda-triggers.html#cognito-user-pools-lambda-trigger-syntax-custom-message – agent420 Nov 08 '17 at 04:30
  • Is this still the case? Why are there callback urls in the App Client Settings in cognito then? – Munib Aug 14 '18 at 20:39
  • The callbacks are for authentication i.e login & not confirmation – agent420 Aug 15 '18 at 05:15
  • Can this same technique be used for forgot password? – Cliff Helsel Jun 20 '19 at 01:58
  • the get request to actual link always response in 200 even when there is error in response "Invalid link provided" – AbhimanuSharma Jul 31 '21 at 05:33
  • When user will be redirected to a https://myapp.com is there a way how I can make him authorized without sign-in? – Volod May 03 '23 at 00:37
15

I got this to work with the help of above answer from @agent420 and examining the github issue https://github.com/aws-amplify/amplify-js/issues/612

So here is the complete process that I followed.

  • First we need to change the verification method to code from link since we need to grab the code when confirming the user through lambda. To do this in Cognito(AWS Console), go to Message customizations -> Verification type, change it to 'Code'.
  • Next we will be adding a lambda trigger to be fired before sending the email verification. To add a lambda for this go to Lambda(AWS Console) and Create a function. Given below is the lambda I used.

exports.handler = (event, context, callback) => {
    // Identify why was this function invoked
    if(event.triggerSource === "CustomMessage_SignUp") {
        console.log('function triggered');
        console.log(event);
        // 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/dev/user/confirm'
        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);
};

Your email will be sent with the subject and message specified in event.response.emailSubject and event.response.emailMessage. The user will directed to the url specified in the url variable.

  • To add the trigger Go to, Cognito(Aws-console) Triggers -> Custom message and select the lambda you just created.
  • Since the user will directing to our url we can control the request, confirm the user and redirect to a url of your choice.

I used a lambda for this with the use of AWS APIGateway. Given below is the code I wrote in nodejs where I used a 301 redirect.

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

module.exports.verifyEmailAddress = (req, context, callback) => {

  console.log('req');
  console.log(req);
  const confirmationCode = req.queryStringParameters.code
  const username = req.queryStringParameters.username
  const clientId = req.queryStringParameters.clientId
  const region = req.queryStringParameters.region
  const email = req.queryStringParameters.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;
      const response = {
        statusCode: 301,
        headers: {
          Location: redirectUrl,
        }
      };
    
      return callback(null, response);
    }
  ).catch(
    (error) => {
      callback(error)
    }
  )
}

Replace environmental variables REGION and POST_REGISTRATION_VERIFICATION_REDIRECT_URL with the values of yours according to the requirement.

Yasith Prabuddhaka
  • 859
  • 1
  • 11
  • 17
  • Is there a way to "resend verfication email". So e.g. to re-trigger the CustomMessage_SignUp? – CodingYourLife Oct 23 '20 at 20:08
  • When user will be redirected to `POST_REGISTRATION_VERIFICATION_REDIRECT_URL` is there a way how I can make him authorized without sign-in? – Volod May 03 '23 at 00:38
7

Complete setup guide.

Complete article link: https://medium.com/@jacobjoy/redirect-user-using-amazon-cognito-confirmation-url-d8ccb11bac75

Thank you @yasith starting with simple image to make it clear how we are doing this work around,

enter image description here Step 1: Create a lambda function with the language of your choice, I am going to use node.js for the following example. Please read Custom Message Lambda Trigger before you proceed, https://docs.aws.amazon.com/cognito/latest/developerguide/user-pool-lambda-custom-message.html In this example I am handling only for CustomMessage_SignUp you can customise for others like CustomMessage_ForgotPassword etc. as per your requirement. Copy the below code to your lambda function,

// Creating a custom URL for the user
exports.handler = (event, context, callback) => {
    if(event.triggerSource === "CustomMessage_SignUp") {
        const { codeParameter } = event.request;
        const { userName, region } = event;
        const { clientId } = event.callerContext;
        const { email } = event.request.userAttributes;
        const url = 'https://xxxxxxx.execute-api.eu-west-2.amazonaws.com/prod/redirect'
        const link = `<a href="${url}?code=${codeParameter}&username=${userName}&clientId=${clientId}&region=${region}&email=${email}" target="_blank">Click the link to verify</a>`;
        event.response.emailSubject = "Your verification link";
        event.response.emailMessage = `Thank you for signing up. Click ${link} to verify your email.`;
    }
// CallBack to the lambda for the email trigger
    callback(null, event);
};

Note: The const URL should be updated once you have API Gateway setup.

Step 2: Under you Cognito Trigger choose the custom message and select the lambda function which you have created

Step 3: Create a GET API in your API Gateway Don’t set any authorization or don’t enable any API key required.

enter image description here enter image description here Step 4: Create another Lambda Function to validate and confirm the user.

'use strict';
var AWS = require('aws-sdk');
AWS.config.setPromisesDependency(require('bluebird'));
var CognitoIdentityServiceProvider = new AWS.CognitoIdentityServiceProvider({
    apiVersion: '2019-11-07',
    region: process.env.REGION
});
exports.handler = (req, context, callback) => {
console.log(req);
    const confirmationCode = req.code;
    const username = req.username;
    const clientId = req.clientId;
let params = {
        ClientId: clientId,
        ConfirmationCode: confirmationCode,
        Username: username
    };
//Validating the user
let confirmSignUp = CognitoIdentityServiceProvider.confirmSignUp(params).promise();
//Returning the redirect url
confirmSignUp.then(
        (data) => {
            context.succeed({
                location: process.env.POST_REGISTRATION_VERIFICATION_REDIRECT_URL
            });
        }
    ).catch(
        (error) => {
            callback(error.message)
        }
    )
};

Create a node application in the IDE of your choice and then build using npm install and once your application is build. Create a zip (Inside the root folder 5 file approx. based on your IDE) and upload to your lambda application.

Lambda Handler method should be = index.handler

Set the following in the lambda env variable

POST_REGISTRATION_VERIFICATION_REDIRECT_URL REGION

In your Application you are validating the user in your cognito user pool and returning the URL for the re-direct. Not in Scope: The error scenario can be also handled based on your requirement.

Step5: Go back to the API Gateway, Create a GET request and Put in the Lambda function which you have to created in Step4 and update the mapping template.

enter image description here enter image description here

Step6: Now we have to redirect the request based on your lambda response, Under Method Response in the API Gateway delete the 200 and create a 302 and add the response header Location as per the image,

enter image description here And then in the Integration Response you need remove the 200 and add the 302 and then add the header Mappings value as integration.response.body.location (Be mindful with the character case) enter image description here

Most important Step: Once all setup Deploy the API and update the const URL API in the Lambda Function, created in the step1.

Try creating a test user and user must have got email link something like this, https://xxxx-api.eu-west-2.amazonaws.com/xx/xx/xx/redirect?code=xx&username=xxxxx;clientId=xxxxx;region=eu-west-2&email=test@gmail.com

Jacob Joy
  • 489
  • 6
  • 7
  • thank you very much was searching for something like this. anyway, when I open the recieved link from the email I got {"message":"Missing Authentication Token"}. Do you have an idea how to fix this? – alexrogo Feb 10 '21 at 18:08
  • 2
    How to create the node application mentioned in step 4? – Luis Garcia Feb 12 '21 at 22:12
  • When the user will be redirected is there a way to sign him in? – Volod May 03 '23 at 00:39
1

You can now manually configure a confirmation redirect lambda function when adding the auth resource to your project: amplify add auth. Check it out

Kouder
  • 11
  • 2