Is the Access Token for a Cognito user available serverside?

889 Views Asked by At

I'm dealing with the issue of users not explicitly logging out of a web application after use, which is not secure enough for the use case. It is a React app with AWS Amplify and Cognito.

I plan to do this by tracking sessions in a database (I can capture the start or refresh of a session using a Cognito Lambda trigger written in Go on PostAuthentication_Authentication or TokenGeneration_RefreshTokens events), and expiring sessions using GlobalSignOut after a period of inactivity, but in order to invalidate the user refresh tokens on session abandonment, I need the Access Token, which appears to only be available to the client.

I can get this explicitly on login from the web client, and post it back to the database using GraphQL to record it, but I was surprised to see that it's not available from the Cognito payload sent to the Lambda event triggers. I'm also not sure of how to grab the refreshed token on the client if it refreshes after an hour of continued application use, without adding overhead to every change in the application.

Is there a way to request the current access token for a Cognito user from a server side process like a Lambda function if you're using Amplify on the client for the authentication flows? I cannot see anything in cognitoidentityprovider that allows me to retrieve the access token, but it's clearly needed to use GlobalSignOut.

2

There are 2 best solutions below

0
On

I've found a workable solution that does not involve fetching the Access Token server side. We use AppSync for GraphQL - the access token is passed with each GraphQL request as an authorization header, and it can be accessed in the request template as follows:

#set( $myMap = {
    "field": "${field}",
    "user_id": $context.identity.sub,
    "source_ip": $context.identity.sourceIp,
    "arguments":  $context.arguments,
    "access_token": $context.request.headers.authorization
} )
{
    "version" : "2017-02-28",
    "operation": "Invoke",
    "payload": $util.toJson($myMap)
}

In each Lambda resolver, I simply cache the access token when encountered, so that I always have the latest access token for the current user. My scheduled session manager function then retrieves the access tokens from the cache for any users it detects with an abandoned session and can use it as an input to GlobalSignOut.

0
On

You could use the Authorisation Code Flow with PKCE instead so the client is only exposed to the code which is then exchanged server-side using the token endpoint for cognito user pool / id token, access token and refresh token. You can return the user pool token to the client as that will expire after an hour while keeping the refresh token in your session manager on the server-side allowing you to fetch fresh tokens as needed or invalidate the session based on your requirements.

https://docs.aws.amazon.com/cognito/latest/developerguide/token-endpoint.html