How to parse JWT Token after user Sign In AWS Cognito - amazon-web-services

I already deploy a static web site use AWS S3 and use AWS cognito to handle User Sign in.
The web Site is https://www.tianboqing.com
The HTML page have a Button,When user Click the button,the url will redirect to cognito sign in url.
'https://tianboqing.auth.us-east-1.amazoncognito.com/login?
client_id=4fgb77l991egfiubejfqep3e6e&response_type=token&scope=aws.cognito.signin.user.admin&redirect_uri=https://www.tianboqing.com';
const handleClick = (event) => {
window.location.href =
'https://tianboqing.auth.us-east-1.amazoncognito.com/login?...
};
document.querySelector('button').addEventListener('click', handleClick);
When User sign In,The Cognito will return a new url like this:
https://www.tianboqing.com/#access_token=eyJraWQiOiJrNFdXeWpRZXZiSlwvN3JNRUlVMzFHS0p4YmtBZHpXMExwN0xMT0tiS1BHRT0iLCJhbGciOiJSUzI1NiJ9.eyJzdWIiOiI2ZmNiNTZhOS1kNDhmLTQyYzItYWUyMi1hMzk0NTllNzc5ZDIiLCJ0b2tlbl91c2UiOiJhY2Nlc3MiLCJzY29wZSI6ImF3cy5jb2duaXRvLnNpZ25pbi51c2VyLmFkbWluIiwiYXV0aF90aW1lIjoxNjM1MzAyMDIxLCJpc3MiOiJodHRwczpcL1wvY29nbml0by1pZHAudXMtZWFzdC0xLmFtYXpvbmF3cy5jb21cL3VzLWVhc3QtMV9Zcm9BY0h5R20iLCJleHAiOjE2MzUzMDU2MjEsImlhdCI6MTYzNTMwMjAyMSwidmVyc2lvbiI6MiwianRpIjoiM2EyMjg0YjItNGM2MS00ZDcyLTk4NGYtNzIzNTExMDc3YmZlIiwiY2xpZW50X2lkIjoiNGZnYjc3bDk5MWVnZml1YmVqZnFlcDNlNmUiLCJ1c2VybmFtZSI6IjZmY2I1NmE5LWQ0OGYtNDJjMi1hZTIyLWEzOTQ1OWU3NzlkMiJ9.xKToMEhhSCqSy9ip0ikmdezY9XRz0GIlIdESSThEuLabWL4rFTw1XRQi4Z9OeDLZcmHyemZt0A1o1OvqZLFyrEHLmRAoyg5SIGD2Ic6tExS1PAmmX8Fe3uF7f851DtKMeapxsaNYyaLE3v-_vkJkDwRvUNoz8nOMUCYB3JKJxGPBlMz1yfn-3CXejepKLYeYYDOUaCPmyErfCy84_eQ-ZoEZFd3bH4vZXDNJKFj6W5_C4IZHuIAJveep3dYVq9cLWy3m8BWOAKWVxk6jTt1w0xI5og5jJiEIPn8Ok10WL1s4eEzAN04AYj6e05uzw4Ka_ip4y7VCdnndnTuWAx_5wQ&expires_in=3600&token_type=Bearer
Which contain the access_token to parse.
My question is,How the code can know the new url which contain access_token is return.
Do I need front route or async await or something?
const handleClick = (event) => {
window.location.href =
'https://tianboqing.auth.us-east-1.amazoncognito.com/login?client_id=...';
};
How to get the user token so I can use it to post to dynamodb?

I will suggest to use API Gateway, where you can add Cognito Authorizer for each and every API you deploy to interact with DynamoDB.
Here is the official documentation you can go through to setup your API-Gateway with Cognito, that you want to use to save records in DynamoDB.
You can grab that access token from the Cognito return page and save it as Session Storage in the front-end using JavaScript.
window.sessionStorage.setItem("accessToken", YourAccessToken);
Use the above stored accessToken as Authorization Header when you call that API via AJAX.
var tok = window.sessionStorage.getItem("accessToken")
var xhr = new XMLHttpRequest();
xhr.open("POST", "URL");
xhr.setRequestHeader("Authorization", tok);
xhr.send();
Instead of url forwarding, you can use AWS-Cognito javascript SDK and use Javascript (via AJAX) to authorize a user.
var cognitoUser = new AmazonCognitoIdentity.CognitoUser({
Username: username,
Pool: userPool
});
var authenticationData = new AmazonCognitoIdentity.AuthenticationDetails({
Username: username,
Password: password
});
cognitoUser.authenticateUser(authenticationData, {
onSuccess: function (result) {
// your code here on success
},
onFailure: function (err) {
// your code here if error occurs
}
});

Related

Cannot fetch the authentity token from AWS

I want to fetch the authentication tokens from AWS;
however, I only receive an error telling me
that the client id is not correct.
I was very happy to have found this code on the web,
link: https://docs.aws.amazon.com/cognito/latest/developerguide/authentication.html
and I was able to invoke the last function call,
but it complains about the ClientId, and I have no clue
where to fetch the Clientid from :-(
I am not sure from where to fetch the Client Id and User Pool Id from?
There is also a Client App Id on the AWS web site.
I am looking for something where I only have to provide
the userid and password using node js?
const AmazonCognitoIdentity = require('amazon-cognito-identity-js');
var authenticationData = {
Username : '...',
Password : '...',
};
var authenticationDetails = new AmazonCognitoIdentity.AuthenticationDetails(authenticationData);
var poolData = {
UserPoolId : '...', // From where on the AWS web site can I fetch the correct User Pool Id?
ClientId : '...' // From where on the AWS web site can I fetch the correct client Id?
};
var userPool = new AmazonCognitoIdentity.CognitoUserPool(poolData);
var userData = {
Username : 'karlschmitt',
Pool : userPool
};
var cognitoUser = new AmazonCognitoIdentity.CognitoUser(userData);
cognitoUser.authenticateUser(authenticationDetails, {
onSuccess: function (result) {
var accessToken = result.getAccessToken().getJwtToken();
/* Use the idToken for Logins Map when Federating User
Pools with identity pools or when passing through an
Authorization Header to an API Gateway Authorizer */
var idToken = result.idToken.jwtToken;
console. log("Successful!");
},
onFailure: function(err) {
// alert(err);
console. log("Failure!" + err.message);
},
});
Create Congnito User Pool - Here is a link and grab Pool Id from General Settings
Register your application as a Client - Here is a link and grab client id

flutter_facebook_login and AWS: Invalid login token. Not a valid OpenId Connect identity token

I am new to Flutter and AWS and I made a small project with facebook authentication.
using:
amazon_cognito_identity_dart: ^0.0.22
flutter_facebook_login: ^3.0.0
On AWS I:
Configured an API with a POST method
Created a new Cognito User Pool
Created a new App Client in the new Cognito User Pool
Created a new Cognito Identity Pool with Facebook AppID from Facebook
I have a sign in function
signInFacebook() async {
final facebookLoginResult = await signInWithFacebook();
final credentials = new Credentials(
cognitoIdentityPoolId,
cognitoUserPoolId,
cognitoClientId,
facebookLoginResult.accessToken.token
);
a method signInWithFacebook:
import 'package:flutter_facebook_login/flutter_facebook_login.dart';
Future<FacebookLoginResult> signInWithFacebook() async {
final facebookLogin = FacebookLogin();
final facebookLoginResult = await facebookLogin.logIn(['email']);
return facebookLoginResult;
}
a class Credentials:
import 'package:amazon_cognito_identity_dart/cognito.dart';
class Credentials {
final CognitoCredentials _cognitoCredentials;
final String _token;
Credentials(String identityPoolId, String userPoolId, String clientId, this._token)
: _cognitoCredentials = new CognitoCredentials(identityPoolId, new CognitoUserPool(userPoolId, clientId));
Future<CognitoCredentials> get cognitoCredentials async {
await _cognitoCredentials.getAwsCredentials(_token);
return _cognitoCredentials;
}
}
and a credentials.dart with the Cognito credentials and the endpoint of the API
The problem is when it executes the method:
await _cognitoCredentials.getAwsCredentials(_token);
I get the following error:
CognitoClientException{statusCode: 400, code: NotAuthorizedException, name: NotAuthorizedException, message: Invalid login token. Not a valid OpenId Connect identity token.}
Why is the token I receive from facebook not valid?
Am I missing something?
i solved updating to the
amazon_cognito_identity_dart_2: ^0.1.19
and using the method
await _cognitoCredentials.getAwsCredentials(_token, 'graph.facebook.com');

Decode JWT From AWS Cognito Exposes poolId and Client app secret

I have created an ASP .Net Core application that authenticates against Cognito.
My Authentication Controller looks like:
public class AuthenticationController : Controller
{
[HttpPost]
[Route("api/signin")]
public async Task<ActionResult<string>> SignIn(User user)
{
var cognito = new AmazonCognitoIdentityProviderClient(RegionEndpoint.APSoutheast2);
var request = new AdminInitiateAuthRequest
{
UserPoolId = "ap-southeast-2_mypoolid",
ClientId = "myclientid",
AuthFlow = AuthFlowType.ADMIN_USER_PASSWORD_AUTH
};
request.AuthParameters.Add("USERNAME", user.Username);
request.AuthParameters.Add("PASSWORD", user.Password);
var response = await cognito.AdminInitiateAuthAsync(request);
return Ok(response.AuthenticationResult);
}
}
Startup.ConfigureServices looks like:
services.AddAuthentication("Bearer")
.AddJwtBearer(options =>
{
options.Audience = "client key";
options.Authority = "https://cognito-idp.ap-southeast-2.amazonaws.com/ap-southeast-poolid";
});
I have included this in case it is something I have done in the above.
My Bearer tokens work fine. I auth against Cognito and get my access/id/refresh tokens.
Being new to Cognito and AWS in general and being curious, I ran my tokens at https://jwt.io/ and found that they contained my poolId and clientId. I was under the impression these are to be hidden away with the utmost security.
Is this normal or is it something I have done. I feel that maybe this shouldn't be exposed so easily?
Yes its normal, Only the secret should not be exposed.

AWS Cognito js: getCurrentUser() returns null

Building a simple application using the examples on their github page. I can log into my application using Cognito. What I can not do is logout because no matter what I try I can't get a hold of the user object. I've dorked around with various other calls to no avail (found here on their API page). The only other post on SO I found isn't applicable because I'm not using Federated Identity. The code I'm using is pretty much verbatim what's on the github page, but will post here for convenience:
login code:
var userName = $('#user_name_login').val();
var userPassword = $('#user_password_login').val();
var userData = {Username: userName, Pool : userPool};
var cognitoUser = new AWSCognito.CognitoIdentityServiceProvider.CognitoUser(userData);
var authenticationData = {Username : userName, Password : userPassword};
var authenticationDetails = new AWSCognito.CognitoIdentityServiceProvider.AuthenticationDetails(authenticationData);
cognitoUser.authenticateUser(authenticationDetails, {
onSuccess: function (result) {
// now that we've gotten our identity credentials, we're going to check in with the federation so we can
// avail ourselves of other amazon services
//
// critical that you do this in this manner -- see https://github.com/aws/amazon-cognito-identity-js/issues/162
// for details
var loginProvider = {};
loginProvider[cognitoCredentialKey] = result.getIdToken().getJwtToken();
AWS.config.credentials = new AWS.CognitoIdentityCredentials({
IdentityPoolId: identityPoolId,
Logins: loginProvider,
});
// //AWS.config.credentials = AWSCognito.config.credentials;
// AWSCognito.config.credentials = AWS.config.credentials;
// //call refresh method in order to authenticate user and get new temp credentials
// AWS.config.credentials.refresh((error) => {
// if (error) {
// alert(error);
// } else {
// console.log('Successfully logged in!');
// }
// });
// this is the landing page once a user completes the authentication process. we're getting a
// temporary URL that is associated with the credentials we've created so we can access the
// restricted area of the s3 bucket (where the website is, bruah).
var s3 = new AWS.S3();
var params = {Bucket: '********.com', Key: 'restricted/pages/user_logged_in_test.html'};
s3.getSignedUrl('getObject', params, function (err, url) {
if (err) {
alert(err);
console.log(err);
}
else {
console.log("The URL is", url);
window.location = url;
}
});
},
mfaRequired: function(session){
new MFAConfirmation(cognitoUser, 'login');
},
onFailure: function(err) {
alert("err: " + err);
},
});
I'm attempting to logout by executing:
userPool.getCurrentUser().signOut();
Note that the userPool and such are defined in another file, and is initialized thusly:
var poolData = {
UserPoolId : '*****',
ClientId : '*****'
};
var userPool = new AWSCognito.CognitoIdentityServiceProvider.CognitoUserPool(poolData);
so how do I sign my users out of the application?
closing this as the issue, as stated here, turned out to be a red herring. if you're doing what I was trying to do above in using cognito to generated a signed url to access an html file located in a restricted 'folder' in the bucket and you want to be able to logout from that new window location, make sure the signed url is of the same domain as your landing page.
for example, if you land at foo.com because you've got an A or CNAME DNS record set up so that your users don't have to hit a doofy cloudfront or s3 generated url in order to get to your website, you need to make sure you ALSO generate a signed URL that has the same domain name. Otherwise you won't be able to access the bucket. Moreover - you won't be able to access your user object because the session object is keyed to a different domain name than the one you're currently at.
see this for information on how to specify what the domain of the signed url should be.
and also note that there's a lot of trouble you can get into if you are using a third-party domain registar. I just burned two weeks unborking myself because of that :-/

AWS API Gateway / Cognito Userpools / Lambdas not able to pass caller credentials

I'm working on an AWS API Gateway implementation with a Lambda backend. I use the API Gateway integration with the Cognito Userpools (fairly new) instead of building a custom authorizer using Lambda (which was the recommended way before it was integrated).
I've created a proof of concept (javascript) that authenticates a user with Cognito and then makes a call to the API Gateway with those credentials. So, basically, the end call to the API Gateway is with the JWT token that I received from Cognito (result.idToken.jwtToken) in the Authorization header. This all works and I can validate that only with this token you can access the API.
All working fine, but now I want to get access to the Cognito identity in my Lambda; for instance the identy id or the name or email. I have read how to map all the parameters, but I'm actually just using the standard 'Method Request Passthrough' template in the integration request. I log all the parameters in the lambda and all the 'cognito' parameters are empty.
I've looked through many similar questions and they all propose to enable the 'Invoke with caller credentials' checkbox on the integration request. That makes perfect sense.
However, this checkbox can only be enabled if you are using AWS_IAM as authorization and not if you have selected your cognito UserPool. So it is just not possible to select it and is actually disabled.
Does anybody know what to do in this case? Is this still work in progress, or is there a reason why you can't enable this and get the cognito credentials in your Lambda?
Many thanks.
If you need to log the user information in your backend, you can use $context.authorizer.claims.sub and $context.authorizer.claims.email to get the sub and email for your Cognito user pool.
Here is the documentation about Use Amazon Cognito Your User Pool in API Gateway
For anyone else still struggling to obtain the IdentityId in a Lambda Function invoked via API-Gateway with a Cognito User Pool Authorizer, I finally was able to use the jwtToken passed into the Authorization header to get the IdentityId by using the following code in my JavaScript Lambda Function:
const IDENTITY_POOL_ID = "us-west-2:7y812k8a-1w26-8dk4-84iw-2kdi849sku72"
const USER_POOL_ID = "cognito-idp.us-west-2.amazonaws.com/us-west-2_an976DxVk"
const { CognitoIdentityClient } = require("#aws-sdk/client-cognito-identity");
const { fromCognitoIdentityPool } = require("#aws-sdk/credential-provider-cognito-identity");
exports.handler = async (event,context) => {
const cognitoidentity = new CognitoIdentityClient({
credentials: fromCognitoIdentityPool({
client: new CognitoIdentityClient(),
identityPoolId: IDENTITY_POOL_ID,
logins: {
[USER_POOL_ID]:event.headers.Authorization
}
}),
});
var credentials = await cognitoidentity.config.credentials()
var identity_ID = credentials.identityId
console.log( identity_ID)
const response = {
statusCode: 200,
headers: {
"Access-Control-Allow-Headers": "*",
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Methods" : "OPTIONS,POST,GET,PUT"
},
body:JSON.stringify(identity_ID)
};
return response;
}
After a Cognito User has signed in to my application, I can use the Auth directive of aws-amplify and fetch() in my React-Native app to invoke the lambda function shown above by sending a request to my API-Gateway trigger (authenticated with a Cognito User Pool Authorizer) by calling the following code:
import { Auth } from 'aws-amplify';
var APIGatewayEndpointURL = 'https://5lstgsolr2.execute-api.us-west-2.amazonaws.com/default/-'
var response = {}
async function getIdentityId () {
var session = await Auth.currentSession()
var IdToken = await session.getIdToken()
var jwtToken = await IdToken.getJwtToken()
var payload = {}
await fetch(APIGatewayEndpointURL, {method:"POST", body:JSON.stringify(payload), headers:{Authorization:jwtToken}})
.then(async(result) => {
response = await result.json()
console.log(response)
})
}
More info on how to Authenticate using aws-amplify can be found here https://docs.amplify.aws/ui/auth/authenticator/q/framework/react-native/#using-withauthenticator-hoc