0

I'm using Appsync with the AWS_IAM authorization type. The identity of the user is provided in the $context.identity of the resolver:

{
"accountId": "123456789",
"cognitoIdentityAuthProvider": "\"cognito-idp.eu-west-1.amazonaws.com/eu-west-1_ABCDABCD\",\"cognito-idp.eu-west-1.amazonaws.com/eu-west-1_ABCDABCD:CognitoSignIn:SomeGuid\"",
"cognitoIdentityAuthType": "authenticated",
"cognitoIdentityId": "eu-west-1:SomeGuid",
"cognitoIdentityPoolId": "eu-west-1:SomeGuid",
"sourceIp": [
    "123.456.78.9"
],
"userArn": "arn:aws:sts::123456789:assumed-role/some-role-name/CognitoIdentityCredentials",
"username": "ABCD1234:CognitoIdentityCredentials"
}

For now I'm using the cognitoIdentityId as the primary identifier of the user in my application. I'm happy to switch to accountId if needs be. My only requirement is that the primary identifier comes from identity object shown above, since I don't want to add additional request just to get the ID.

The problem: I have a workflow that requires a user to exist before the person logs in and uses the application. So I need to create the user and assign data to it. Somewhere down the line, the person may actually login for the first time and should have access to data that has been assigned to the user.

I can create the user in Cognito, but I can't seem to find a way to retrieve or generate the accountId or the cognitoIdentityId of the user that they would have when they eventually login to the application. Please help.

Edit #1

I figured out accountId has nothing to do with the user identity. It is the accountId of the AWS user that deployed the service (Appsync or Cognito, I don't know). So it is the same for all users.

So my question remains, how do I generate or retrieve the cognitoIdentityId of a user after creating it in the Cognito User Pool?

Community
  • 1
  • 1
Casper Alant
  • 452
  • 5
  • 15
  • Have you checked the Auth.signing method? it gives everything you need to identify a user – dfranca Apr 22 '20 at 13:44
  • I'm hesitant to use Amplify on the backend. However, it looks like I have to do this by logging in as the user. I'm currently trying to use Cognito AdminInitiateAuth to do this. – Casper Alant Apr 22 '20 at 14:05

1 Answers1

1

I figured out a solution the essentially logs in as the user in order to get Cognito Identity ID:

import { config, CognitoIdentityServiceProvider, CognitoIdentity } from 'aws-sdk';
config.update({
  region: process.env.REGION,
  apiVersions: {
    cognitoidentityserviceprovider: '2016-04-18',
    cognitoidentity: '2014-06-30',
    // other service API versions
  }
});

export async function createUser(name: string, given_name: string, family_name: string, phone_number: string) {
  var cognitoidentityserviceprovider = new CognitoIdentityServiceProvider();
  var params = {
    UserPoolId: process.env.USER_POOL_ID,
    Username: phone_number, /* required */
    MessageAction: "SUPPRESS",
    UserAttributes: [
      {
        Name: 'name', /* required */
        Value: name
      },
      {
        Name: 'given_name', /* required */
        Value: given_name
      },
      {
        Name: 'family_name', /* required */
        Value: family_name
      },
      {
        Name: 'phone_number', /* required */
        Value: phone_number
      },
      {
         Name: "phone_number_verified",
         Value: "true"
      }
    ]
  };

  console.log("adminCreateUser")
  let adminCreateUserResonse: CognitoIdentityServiceProvider.AdminCreateUserResponse = await new Promise(resolve => {
    cognitoidentityserviceprovider.adminCreateUser(params, function(err, data) {
      if (err) console.log(err, err.stack); // an error occurred
      else {
        console.log(data);           // successful response
        console.log("adminCreateUser complete")
        resolve(data)
      }
    })
  });

  let identity: CognitoIdentity.GetIdResponse = await new Promise(resolve => {
    setPassword(phone_number, resolve)
  });

  let user_attributes = adminCreateUserResonse.User.Attributes
  let sub = user_attributes.find(a => a.Name == "sub")

}

function setPassword(phone_number: string, resolve: any) {
  var cognitoidentityserviceprovider = new CognitoIdentityServiceProvider();
  let password = generator.generate({
    length: 32,
    numbers: true,
    symbols: true,
    lowercase: true,
    uppercase: true
  });

  var setPasswordParams = {
    Password: password, /* required */
    UserPoolId: process.env.USER_POOL_ID, /* required */
    Username: phone_number, /* required */
    Permanent: true
  };

  console.log("adminSetUserPassword")
  cognitoidentityserviceprovider.adminSetUserPassword(setPasswordParams, function(err, data) {
    if (err) console.log(err, err.stack); // an error occurred
    else {
      console.log(data);           // successful response
      console.log("adminSetUserPassword complete")
      initiateAuth(phone_number, password, resolve)
    }
  })
}

function initiateAuth(phone_number: string, password: string, resolve: any) {
  var cognitoidentityserviceprovider = new CognitoIdentityServiceProvider();
  let initiateAuthParams = {
    AuthFlow: "ADMIN_USER_PASSWORD_AUTH",
    AuthParameters: {
      "USERNAME" : phone_number,
      "PASSWORD" : password
    },
    UserPoolId: process.env.USER_POOL_ID, /* required */
    ClientId: process.env.CLIENT_ID
  }
  console.log("adminInitiateAuth")
  cognitoidentityserviceprovider.adminInitiateAuth(initiateAuthParams, function(err, data) {
    if (err) console.log(err, err.stack); // an error occurred
    else {
      console.log(data);           // successful response
      console.log("adminInitiateAuth complete")
      getId(data, resolve)
    }
  })
}

function getId(data: CognitoIdentityServiceProvider.AdminInitiateAuthResponse, resolve: any) {
  const cognitoidentity = new CognitoIdentity()
  let login_provider = "cognito-idp." + process.env.REGION + ".amazonaws.com/" + process.env.USER_POOL_ID
  console.log("login_provider: " + login_provider)
  let getIdParams = {
    "AccountId": process.env.AWS_ACCOUNT_ID,
    "IdentityPoolId": process.env.IDENTITY_POOL_ID,
    "Logins": {}
  }
  getIdParams.Logins[login_provider] = data.AuthenticationResult.IdToken
  console.log("getId")
  cognitoidentity.getId(getIdParams, function(err, data) {
    if (err) console.log(err, err.stack); // an error occurred
    else {
      console.log(data);           // successful response
      console.log("getId complete")
      resolve(data)
    }
  })
}
Casper Alant
  • 452
  • 5
  • 15
  • If you're using Cognito User Pools you can use the user pool sub as identifier in your application if you have user pools authorization on your API. You wouldn't need to federate your user pool with Cognito Federated Identities to get AWS credentials. – Ionut Trestian Apr 26 '20 at 22:09