The doc here says, you can connect with AWS API gateway with either the access token or the idToken issued by the cognito.
I am using amazon-cognito-identity-js for one of my Angular project. Once I login, I receive three tokens viz. accessToken, idToken and refreshToken which the sdk stores to the local storage.
Using the idToken as the Authorization header in the subsequent call successfully provides me data from the API gateway integration method, while if I use accessToken I receive a 401-Unauthorised and the response header says:
x-amzn-errortype: UnauthorizedException
Can the access token not be used for the above purpose. I am fine with using idToken, except that there are known issues in invalidating the idToken even after cognito.user.signOut or even globalSignOut as explained here.
Can someone suggest why the access token might not be working.
You can use the access token against an API endpoint if you are validating any custom scopes. In other words, if you haven't defined any custom scopes for your app client, you will use id token to call the API endpoint. otherwise, you can use an access token to validate any custom scopes.
Hope this helps.
Reference:
https://docs.aws.amazon.com/cognito/latest/developerguide/amazon-cognito-user-pools-using-tokens-with-identity-providers.html#amazon-cognito-user-pools-using-the-access-token
Related
I have a cognito user pool/app client setup with OAuth flow and standard scopes (email, admin, etc.) and several 3rd party providers (google, azure, etc.). I would like to get the identity data in the request context which mean I would need to use the id token but using the id token gets me an unauthorized response from api gateway while the access token works as expected. I remember reading somewhere that custom scopes doesn't allow for id token auth but I don't have custom scopes setup. Any insight into what's going on here?
From Integrate a REST API with an Amazon Cognito user pool:
With the COGNITO_USER_POOLS authorizer, if the OAuth Scopes option
isn't specified, API Gateway treats the supplied token as an identity
token and verifies the claimed identity against the one from the user
pool. Otherwise, API Gateway treats the supplied token as an access
token and verifies the access scopes that are claimed in the token
against the authorization scopes declared on the method.
OAuth Scopes are only present in access tokens. Based on the fact that access tokens work, you have specified one or more OAuth scopes for your endpoint.
If you have a valid access token, you can use its value to get information about the authenticated user using the USERINFO endpoint.
I am trying to test an API Gateway endpoint, using Postman.
I'm trying to make use of the Hosted UI, and whilst I can get an access_token returned in the URL, using this in the Authorization Bearer Token, I simply get 401 Unauthorized responses.
The specific endpoint has the correct authorizer attached to it.
I even tried removing the authorizer all together, but still got the 401 response, so I'm quite confused, as that should have meant I don't need to pass any token with the request?
Turns out, despite the naming convention, access_token was the wrong token to use. I tried th id_token and that works.
Solution: Add an OAuth scope if you want to use the access token otherwise use an id token.
From the documents
With the COGNITO_USER_POOLS authorizer, if the OAuth Scopes option isn't specified, API Gateway treats the supplied token as an identity token and verifies the claimed identity against the one from the user pool. Otherwise, API Gateway treats the supplied token as an access token and verifies the access scopes that are claimed in the token against the authorization scopes declared on the method.
Consider a restapi backend consisting of AWS-ApiGateway and -Lambda.
After successful oauth2 authentication, AWS Cognito returns both an access_token and an id_token to the client in the code authorization grant flow.
During api calls, the lambda function needs to know the email address of the authenticated client, so I basically have 2 choices:
Send the id_token in the Authorization header which is validated by the ApiGateway and passed to the Lambda. Let Lambda decrypt the id_token and access the email address contained in it.
Send the access_token in the Authorization header which is validated by the ApiGateway with scope=openid email and passed to the Lambda. Let Lambda make a GET call to the /oauth2/userinfo endpoint with the access_token in the Authorization header to obtain email address.
Which of both is best practice? Why?
Good question:
Access tokens are designed to be short lived API credentials, containing scopes / claims etc
Id tokens have a different role, to provide proof of authentication to a client, as in my blog post
However, if you are using AWS Cognito then there is a vendor limitation that access tokens cannot be customised - eg to include email address.
So it can be common for an API or a Gateway to do more work when a token is first received - eg to look up user info or claims from other sources - then cache them for subsequent requests with the same access token.
That is, option 2 is preferred, rather than using an id token in an unnatural way.
For further info on this design pattern see:
Claims Blog Post
Sample Code
Not sure if you're looking into API Gateway custom authorizers, but if so my blog has some stuff on this here
I'm building an API using the serverless framework. I'm trying to authenticate requests coming in through API Gateway by leveraging Cognito (UserPools), and giving each of my users their own authorization token for each API call they make.
Trying to test it with postman I'm not able to make a call and pass authorization. I've tried setting Authorization in the header with the App Client Secret, but I'm just getting "Unauthorized" back. Is there something I'm missing?
You should be using the token rather than the App Client Secret. How are you retrieving the token?
For user sign in authorization, you must be sure you uncheck the option to generate client secret when you are creating a new Client Application inside UserPool.
In your API Gateway you create an authorizer making a reference to you before created UserPool. Inform "authorization" for the header.
Using a AWS third party SDK service (or just their API), signin with a valid user. You will get 2 types of tokens after the login, make sure you keep the right one. I advise you to check the token through the API Gateway authorizer testing option. Note: This step is the most important, as you are isolating the token you get and the authorization service. This way you can track the source of your problem.
So I'm using cognito User Pools with Google as an Identity provider. I configured everything and I'm sending the data to google, which redirects back to the amazon auth endpoint, which then redirects back to my app with the following parameters in the URL:
AccessToken
ExpiresIn
IdToken
TokenType
Now, I have no idea how to use these to actually create a Cognito "session" that goes into the javascript api workflow and just becomes automatic (sending, receiving and renewing the token)
How do I achieve this?
Using IDToken to Authenticate Your API
After you authenticate, you can cache the IDToken in Browser and use it when the logged in user requests for API Calls from your web or mobile application. Then you can validate the token at your API endpoints for each request.
Validating IDToken
For more information about using the tokens and validating it at API endpoints, refer AWS documentation on Using Tokens with User Pools. There is a new library introduced by AWS called aws-amplify which simplify some of the implementations. If you are using AWS API Gateway for your API, you can use a custom authorizer Lambda function to do the validation.
Storing the IDToken and Security
In addition, the IDToken is a stateless token, which means it doesn't have a session in connection with AWS Cognito Once issued. Which means you cannot revoke it after issuing. Therefore it's important to keep its expiry short.
To allow your authentication API to issue new IDTokens before it gets expired, you might need to store the Refresh Token in your backend and use it to issue new tokens before the IDToken expires to implement a sliding window.
Note: Storing the IDToken in browser, you can decide in using multiple storage options available (E.g; Cookies, LocalStorage). However, I'm not going to comment on the security implications since it is itself a long discussion where there are still opinionated areas. The standard approach currently available, is to set up a serverside Cookie and implement CSRF. It will be challenging to implement unless you use the IDToken just to initiate the authentication and use a session instead, for the recurring requests.