I currently have an API Gateway setup to tie in Lambda functions which are written using Java. I'm using the javascript SDK to call the API Gateway endpoints and they are correctly relaying to the Lambda functions. However when I try to access the Cognito Identity ID via:
context.getIdentity()
I get the following response:
lambdainternal.api.LambdaCognitoIdentity#xxxxxx
If I run
context.getIdentity().getIdentityId()
It just returns a empty string in the logger. Not sure what I need to do to get the Identity ID for the user making the request to pass through to the context.
I'm generating the Javascript AWS Api Client via the following:
var apiClient = apigClientFactory.newClient({
accessKey: credentials.accessKeyId,
secretKey: credentials.secretAccessKey,
sessionToken: credentials.sessionToken,
region: 'us-east-1'
});
The lambda functions are secured using IAM policies and the user is able to access the lambda functions so authentication is working correctly. It's just not providing the IdentityId for some reason.
In order for Lambda to access the Cognito identity in its own context variable, you need to enable the checkbox "Invoke with caller credentials" on the Integration Response tab.
Alternatively, you could also use API Gateway's mapping templates and pass the value of $context.identity.cognitoIdentityId to your Lambda function. The mapping template would look something like this:
{
"cognito-identity" : "$context.identity.cognitoIdentityId"
}
Please also have a look at one of API Gateway's forum discussions for more details / background information (How to pass cognito identity id to backend through API Gateway).
Try using event.requestContext.authorizer.claims. You have access to cognito:username, email and other stuff that gets crammed in the token when it's generated. You can even customize this with Cognito's pre token generation trigger.
Related
We have a React client that uses AWS Cognito and Amplify ("aws-amplify": "1.1.40").
When a user logs in we want to send some additional data to Cognito, to be used by a "pre token generation" trigger. We do this by adding a clientMetadata ({"metadataKey1": "metadataValue1"}) object to the Auth.signIn function call:
Auth.signIn(auth.email, auth.password, {"metadataKey1": "metadataValue1"})
.then(response => {
// Sign in OK
})
.catch(error => {
// Something went wrong
});
This works as expected, and the Cognito "pre token generation" lambda can extract the "metadataKey1" from the clientMetadata in the request.
This is where our problem starts:
After the successful signIn, AWS Amplify automatically does a session refresh. This session refresh is not explicitly done by our code, and the clientMetadata object used during signIn is not set. This of course means that the automatic session refresh request to Cognito does not contain the clientMetadata, which in turn means that the Cognito "pre token generation" lambda can not extract "metadataKey1" from the clientMetadata in the request (as it does not exist).
We have debugged the code, and found that the automatic request to Cognito happens in #aws-amplify\auth\node_modules\amazon-cognito-identity-js\es\CognitoUser.js#1249, CognitoUser.prototype.refreshSession. The refreshSession function can receive a clientMetadata object, but when debugging the code the clientMetadata object is always undefined (which makes sense; we have not set it explicitly and the Amplify code does not seem to store/use the clientMetadata we set during signIn).
What we need help with:
Are we not doing enough? Do we have to do some other things in our code to make sure the clientMetadata object is sent on every request to Cognito, even requests that are not explicitly done by our code?
Are we doing it wrong? The goal is to make sure we can send our own data on every request to Cognito. Are there other ways to do this than use the clientMetadata object?
Would really appreciate any help with this!
According to API Reference, The ClientMetadata value is passed as input to the functions for ONLY the following triggers:
Pre signup
Pre authentication
User migration
I want my users to login using the Sign In With LinkedIn feature. The LinkedIn API docs provides the following example snippet for getting started:
<script type="text/javascript" src="//platform.linkedin.com/in.js">
api_key: YOUR_API_KEY_HERE
authorize: true
onLoad: onLinkedInLoad
</script>
<script type="text/javascript">
// Setup an event listener to make an API call once auth is complete
function onLinkedInLoad() {
IN.Event.on(IN, "auth", getProfileData);
}
// Handle the successful return from the API call
function onSuccess(data) {
console.log(data);
}
// Handle an error response from the API call
function onError(error) {
console.log(error);
}
// Use the API call wrapper to request the member's basic profile data
function getProfileData() {
IN.API.Raw("/people/~").result(onSuccess).error(onError);
}
</script>
How to I implement this without exposing YOUR_API_KEY_HERE to the public? There's a few npm packages out there that handle this kind of thing, but they are all old (I get nervous whenever a package hasn't been updated in at least a year).
My application uses node and express. Should I go with an old npm package or is there a better way to hide the api_key?
It is ok and necessary to have YOUR_API_KEY_HERE in the javascript or website and it is necessary at times. They important piece is not to share your SECRET_KEY because you need both to do anything with the API. Be sure to always use HTTPS for all communications.
From the linkedin best practices for security application website:
https://developer.linkedin.com/docs/best-practices
API Key & Secret Key
When making calls to the LinkedIn APIs you use two pieces of identifiable information: the API Key (sometimes called the Consumer Key) and the Secret Key (or Consumer Secret).
The API Key is a public identifier of your application and the Secret Key is confidential and should only be used to authenticate your application on the LinkedIn APIs.
Since both the API Key and Secret Key are needed together to confirm your application’s identity, it is critical that you never expose your Secret Key. Here are some suggestions for proper Secret Key storage:
When creating a native mobile application, do not store it locally on a mobile device.
Do not expose in any client side code files like JavaScript or HTML files.
Do not store it in files on a web server that can be viewed externally e.g.: configuration files, include files, etc.
Do not store it in log files or error messages.
Do not email it or post it on a message board or other public forum.
Remember that when exchanging an OAuth 2.0 authorization code for an access token, the Secret Key is passed as part of the request. Do not expose this request publicly!
I just started using google on-tap sing-in/sign-up in my new app.
It works perfectly except that I don't know how can I ask user permissions to access scoped data?
client.verifyIdToken(
token,
CLIENT_ID,
function(e, login) {
var payload = login.getPayload(); // <-- payload just containt name,email and picture. I want more
var userid = payload['sub'];
});
You can use Google Sign-In to authorize more scopes. Pass the email address of the account returned by One-Tap as the login_hint parameter to the gapi.auth2.init call, then call gapi.auth2.getAuthInstance().signIn() so that the user can grant access to the other scopes your app require.
You can also use gapi.auth2.authorize for One-Off authorization (if you use gapi.client to perform requests to Google APIs, you generally want to use init/signIn).
I am trying to get a login procedure to work in AWS by following the Enhanced Authflow for Developer Authentication mentioned in the official documentation.
The code in both client and server are using JavaScript, and I'm using Node.js on the server-side.
I have managed to get the OpenId token back to the client but when I try to exchange it for credentials by calling getCredentialsForIdentity(), the client receives this error:
NotAuthorizedException: Access to Identity 'eu-west-1:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx' is forbidden.
Also on the server-side when I print the variable holding my AWS.CognitoIdentity object and check the property cognitoidentity.config.credentialProvider all I get is:
{"providers":[null,null,null,null]}
It feels like the named custom developer provider I have associated with my identity pool should be in there but I seem to not be able to get it there.
Any thoughts on where I might have gone wrong?
That error is usually thrown when you try to get access to an authenticated id without providing any of the tokens linked to that identity. If it's an authenticated identity, make sure you are giving a token for it.
I am trying to use the javascript sdk to do an oauth login and access the google plus api. Basically the same code here: https://developers.google.com/api-client-library/javascript/features/authentication
In my firebug console, this is the url that is sending the api request to:
https://content.googleapis.com/discovery/v1/apis/plus/v1/rest?fields=servicePath%2Cresources%2Cparameters%2Cmethods&pp=0&key={key}
This is the error that comes back:
{"error":{"errors":[{"domain":"usageLimits","reason":"keyInvalid","message":"Bad Request"}],"code":400,"message":"Bad Request"}}
I have:
1. Added Google Plus Api to my project
2. Created oauth credentials
3. Setup my consent screen
However, I am still getting the error.
The reason is that you have the key defined in the request. As specified in the discovery API docs (https://developers.google.com/discovery/v1/getting_started#before_starting):
"The APIs Discovery Service provides only public methods that do not
require authentication. In addition, unlike the requests you make to
many other Google APIs, the requests you make to the Discovery Service
API should not include an API key. If you do provide a key, the
requests will fail. This behavior helps ensure that you don't
accidentally disclose your API key when distributing tools that are
based on the Google APIs Discovery Service."
So you can solve the problem by removing the key from your request entirely.
If you are using Google's javascript client to do this and the error occurs when loading further APIs, you have to unset the key first:
gapi.client.setApiKey( null );
gapi.client.load( "plus", "v1", function( apiresponse ) { ... } );
If another function requires the key later, you have to set it again.
To avoid setting and unsetting the key constantly, I load all the needed APIs before authentication, then set the API key and thus will no longer have the issue.