Cognito: Let server act on behalf of user

0

I'm building an HTTP JSON API using API Gateway with a Lambda authoriser that verifies a passed id token (and checks some other properties of the request) and sends info about the user to the backend.

I now need a server that acts on behalf of users. Users message that server using a third party (think Signal or WhatsApp) and the server calls some API methods on their behalf. That server knows which third party account the message is coming from and should check whether there is a Cognito user with that account in the user pool. (The third party isn't an identity provider, so we aren't using identity pools but are just storing an account id.)

How can I authenticate the server towards the API? Can I get an id token without the users credentials and without a refresh token but just with admin access to Cognito or do I have to add another custom authorisation path to the API? Is this way of authentication secure?

1 Answer
1

You can use Cognito's "Admin Initiate Auth" operation to authenticate the server to the API. This operation allows you to authenticate users as an administrator. You won't need to use user credentials or a refresh token this way.

Here are the steps to take:

  1. Create an IAM role with appropriate permissions for your server to access Cognito's Admin APIs. You must specifically grant the "cognito-idp:AdminInitiateAuth" permission.
  2. When you receive a message from a third-party service (such as Signal or WhatsApp), use the account ID to find the corresponding Cognito user in your user pool.
  3. To authenticate the user and obtain an ID token, use the Cognito "Admin Initiate Auth" API:
import boto3

client = boto3.client('cognito-idp')

response = client.admin_initiate_auth(
    UserPoolId='your-user-pool-id',
    ClientId='your-app-client-id',
    AuthFlow='ADMIN_USER_PASSWORD_AUTH',
    AuthParameters={
        'USERNAME': 'user_name',  # The user's Cognito username
        'PASSWORD': 'user_password',  # A temporary password or the user's actual password
    },
    ClientMetadata={
        'third_party_account_id': 'account_id',  # The third-party account ID
    }
)
  1. Make a call to your API on behalf of the user using the ID token you obtained.
  2. Verify the ID token in your Lambda authorizer and look for the third-party account ID in the "ClientMetadata" section. Make decisions based on the user's permissions using this information to validate the request.

This approach is secure as long as best practices for handling access keys and tokens are followed. Make sure to secure your server's IAM credentials and any sensitive data.

Keep in mind that using "Admin Initiate Auth" on the server involves handling user passwords, which could be a security risk. Consider using OAuth 2.0 with a custom grant type or implementing a separate custom authentication flow for your server that does not require user credentials if possible.

profile picture
EXPERT
answered a year ago

You are not logged in. Log in to post an answer.

A good answer clearly answers the question and provides constructive feedback and encourages professional growth in the question asker.

Guidelines for Answering Questions