I am building a serverless react app which uses Cognito for sign-in/sign-out. The app calls API Gateway which is configured to use the Cognito User pool as the custom authorizer.
I also build a lambda function to sign out a user (cognitoIdentityServiceProvider.globalSignOut).
When I sign into the app, and then call the lambda function to perform an admin sign-out, calls to protected API gateway functions from the app are still valid (with Cognito ID token passed in Authorization header);
Are admin calls such as cognitoIdentityServiceProvider.globalSignOut and cognitoIdentityServiceProvider.adminUserGlobalSignOut not realtime, or is API Gateway configured to only validate after an hour?
Just found the answer, unfortunately not what I wanted to hear:
Because IdToken is represented as a JSON Web Key Token, it's signed
with a secret or private/public key pairs, which means even if you
revoke the IdToken, there is no way to revoke the distributed public
key. And IdToken has a short life span, it will expire in a short
time.
Is it possible to revoke AWS Cognito IdToken?
https://github.com/aws/aws-sdk-js/issues/1687
https://github.com/aws/amazon-cognito-identity-js/issues/21
It is the default settings of Cognito user pool. The access token expires one hour after the user authenticates. It should not be processed after it has expired.
You can revoke all user token though using the GlobalSignOut and AdminUserGlobalSignOut APIs. After the user has been signed out:
The user's refresh token cannot be used to get new tokens for the user.
The user's access token cannot be used against the user pools service.
The user must reauthenticate to get new tokens.
An app can use the GlobalSignOut API to allow individual users to sign themselves out from all devices. Typically an app would present this option as a choice, such as Sign out from all devices. The app must call this method with the user's valid, nonexpired, revoked access token. This method cannot be used to allow a user to sign out another user.
An administrator app can use the AdminUserGlobalSignOut API to allow administrators to sign out a user from all devices. The administrator app must call this method with AWS developer credentials and pass the user pool ID and the user's username as parameters. The AdminUserGlobalSignOut API can sign out any user in the user pool.
Please have a look on official documentation:- http://docs.aws.amazon.com/cognito/latest/developerguide/amazon-cognito-user-pools-using-tokens-with-identity-providers.html
I am on the Cognito team. globalSignOut revokes the access token and the refresh token. The id token is a bearer token, that is used with systems external to User Pools. API Gateway will still accept it, but it's validity is of 1 hour.
Related
I'm building a REST API and using AWS Cognito's user pools for authentication. I've got a "get_token" endpoint that returns the JWT access and refresh tokens to the user, which they use to authenticate access to the other REST endpoints provided by the API.
The access token has an expiration timeout. If the user of my API is an application program, what are the best practices for the application to handle when the access token expires? Does the application have to remember the username/password and re-authenticate to continue? Is using the refresh token to get a new access token and use that going forward the best approach?
Is there any documentation, suggestions anyone can point out that might help me out?
Cognito provides 3 types of tokens, id, access and refresh tokens when you login. The way this usually works is that you send either of the first two (depends on whether you want to be sending user payload information to your backend) to your backend via an Authorization header and verify the token there.
Your id and access tokens usually have a shorter expiration time compared to the refresh token. What you should do is, when the id (or access) token expire, you should use the refresh token to generate a new id (or access) token. When the refresh token expires that means that you can no longer generate new id/access tokens from it. In this case, the user (or app) must login again.
In my application, users can perform some tasks without login via the keycloak. After performing the task, I want to get an access token from keycloak by giving the username of the user to automatically log the user into application. Assume the user has a registered user account in keycloak too. is there a way to obtain an access token with username only?
In my application, users can perform some tasks without login via the
keycloak.
Unless those users are authenticated via some external IDP and you have established a trust-relationship between your external IDP and Keycloak (have a look at this SO thread for potential solution for a similar question to yours) in short I would say no.
From auth0:
Access tokens are used in token-based authentication to allow an
application to access an API. The application receives an access token
after a user successfully authenticates and authorizes access, then
passes the access token as a credential when it calls the target API.
The point is exactly that, exchanging some kind of authentication information (.e.g., username and password, or client secret) for a token that proves to your application that the user has authenticated successfully. Otherwise, someone could just enter your system as long as it had access to a username.
It sounds to me that you want to use the access token has means to pass information between Keycloak and your app, for that you have for sure better options.
I'm using Cognito's federated sign in with Sign In With Apple. I have an API Gateway route using a JWT Authorizer through appleid.apple.com From the iOS app, if I pass the identity token to this API Gateway route and it appears to work.
After 10 mins, the Apple identity token expires as expected. Do I have to manually verify a user and fetch a refresh token or does Cognito offer an endpoint to do this for me and return a refresh token?
There is not an ALLOW_REFRESH_TOKEN_AUTH option available.
Cognito offers a refresh token endpoint. When you set up the app client for your userpool in Auth Flows Configuration, the option "ALLOW_REFRESH_TOKEN_AUTH" is already selected by default, then click "save app client changes"
AWS Support said "If you are using Authorization Code grant then refresh token will be generated once the flow is completed. The Authorization code grant flow initiates a code grant flow, which provides an authorization code as the response. This code can be exchanged for access tokens with the TOKEN Endpoint. Because the tokens are never exposed directly to an end user, they are less likely to become compromised." and referenced me here:
https://aws.amazon.com/blogs/mobile/understanding-amazon-cognito-user-pool-oauth-2-0-grants/
My understanding is that upon successful login Cognito provides my service three tokens for a user, access, ID and refresh. In order to verify a token I'm using jsonwebtoken (jwt.verify(accessToken, pem)). This is all fine, I'm able to verify a token and obtain a new access token with my refresh token if it's expired.
However, my accessToken is valid for one hour. If I want to revoke all of a users tokens using cognitoUser.globalSignOut(), that token will pass my JWT verification using the JWT library for 60 mins as that is all done server side.
Is there a way to send a token to AWS Cognito and ask "Hey is this Token still valid?"
This thread might help you understand how a call to globalSignOut() affects the validity of the 3 tokens.
Is it possible to revoke AWS Cognito IdToken?
Cognito does not have an API to check the validity of the token. You will have to call one of your APIs and check if the call was successful or not.
I established a authentication flow with Facebook Login and AWS Cognito on the client site. Works fine. But now I need a reference of the user with its facebook id in a dynambodb table. Of course I could just call a AWS lambda function exposed via AWS API gateway, but how can I verify that the API call actually has a valid facebook id and that this facebook id matches the AWS Cognito Id. Maybe I am missing something here, I hope you guys can point me in the right direction ;) thanks!
If you can key your ddb table by cognito id instead of facebook id, you can invoke api gateway with cognito credentials. If you use callee credentials when calling lambda you can access the cognito id via the token $context.identity.cognitoIdentityId. This ensures the call was made by the owner of this id. You can further check that $context.identity.cognitoAuthenticationProvider is graph.facebook.com to ensure they authed via Facebook. Unfortunately, the facebook id is not passed in the credentials, so if you need it you will need a lookup table mapping cognito id to facebook id. For more details on the available tokens see here.
I would suggest to do the following (I'm new to AWS as well, Let me know if you have any suggestions):
Create a API Gateway /fblogin endpoint where you will POST the Facebook Access Token (You will authenticate with Facebook on the client side to get this token). That endpoint is linked to a Lambda function say fb_login.
In fb_login function you will authenticate with Amazon Cognito to get its credentials. You should have created a Federated Identity user pool in Cognito and assign appropriate roles to assume for this user pool. This helps if you want to restrict your API only to those who are authenticated and authorized. So, the result from Cognito will have IdentityId and Credentials. You can return them as a result of your request to /fblogin.
Using the above result you can sign the requests you send to your API on API Gateway (Or you can use AWS custom generated SDK for your API to handle the signing). On the API Gateway endpoints, enable CORS and authentication as AWS_IAM. This way, API Gateway verifies the user automatically by checking the signature in the request. You can get the User Id from $context.identity.cognitoIdentityId as others suggested. This way, you can be sure that the user is authorized and authenticated.
Note: Make sure you implement /fblogin endpoint on HTTPS, then the FB Access token will be secure. If not, it will be visible as plain text over HTTP.
Also, use a Dynamo DB table as a log for CognitoID - FacebookID. You can incorporate this in the Step 2 Lambda function ifself or anything you think is appropriate.