AWS user pool authentication with external OIDC IdP - amazon-web-services

I'm working on a node/express backend for an app. The authentication process is already setup with Auth0 and passport. But we need to use AWS now...
I've followed these docs and successfully tested the custom endpoint referenced at the end of the article: https://docs.aws.amazon.com/cognito/latest/developerguide/cognito-user-pools-oidc-idp.html
but from here I'd like to connect to a identity pool in order to access AWS services. I keep getting errors, and though I can see the users in the AWS 'user pool', they aren't showing up in AWS 'identity pool'.
i was calling AWS using:
AWS.config.credentials = new AWS.CognitoIdentityCredentials({
IdentityPoolId: IDENTITY_POOL_ID,
Logins: {
"cognito-idp.<region>.amazonaws.com/<user-pool-id>":
id_token_from_provider,
},
})
the main error I keep getting is that the 'login token is invalid: issuer doesn't match the provider id'.
Any help is appreciated...

after some more digging: found this nice walkthrough by Auth0, https://auth0.com/docs/integrations/integrating-auth0-amazon-cognito-mobile-apps
I've skipped the user pool integration and am just using cognito for the 'identity pools'
my credentials map changed some as well:
AWS.config.credentials = new AWS.CognitoIdentityCredentials({
IdentityPoolId: "IDENTITY_POOL_ID",
Logins: {
"<PROVIDER_NAME_FROM_IAM": id_token,
},
})

Related

Is it possible to gain access to AWS resources by Amazon Social Login?

I was requested to create an app that people login using their AWS credentials and the app does actions on AWS resources on their behalf.
Is this possible with oAuth flow, meaning that the users login on AWS and my app received an access token, or the only way to do this is by asking the user to enter his access/secret in my app?
Cognito with User pool and Identity pool is made for this use case.
This is getting started guide. Here are the steps:
Create a pool.
Integrate pool with identity provider.
Setup roles and necessary permissions.
Pass this token to get AWS Credentials.
Sample code to get aws credentials:
AWS.config.credentials = new AWS.CognitoIdentityCredentials({
IdentityPoolId: 'IDENTITY_POOL_ID',
Logins: { // optional tokens, used for authenticated login
'graph.facebook.com': 'FBTOKEN',
'www.amazon.com': 'AMAZONTOKEN',
'accounts.google.com': 'GOOGLETOKEN',
'appleid.apple.com': 'APPLETOKEN'
}
});
AWS.config.credentials.get(function(){
var accessKeyId = AWS.config.credentials.accessKeyId;
var secretAccessKey = AWS.config.credentials.secretAccessKey;
var sessionToken = AWS.config.credentials.sessionToken;
});

Accessing AWS AppSync without using API Keys in React Native

In my React Native App I am using API Keys with AWS AppSync and I want to move to using Cognito or IAM but with no user sign in.
My React Native app that just uses AWS Appsync to read to and write from DyanmoDB.
I initially set up the app to use API keys as it was easier to understand and I'm now attempting to transition to using AWS Cognito or IAM.
To do this in my AWS Console I changed the "Appsync->MyAppAPI->Settings->Default authorisation mode"/"API-level" from "API key" to "AWS Identity and Access Management (IAM)".
I then created an Identity Pool and allowed "Enable access to unauthenticated identities".
My aws-exports file is
// WARNING: DO NOT EDIT. This file is automatically generated by AWS Amplify. It will be overwritten.
const awsmobile = {
"aws_appsync_graphqlEndpoint": "https://xxxxx.appsync-api.eu-west-x.amazonaws.com/graphql",
"aws_appsync_region": "eu-west-X",
"aws_appsync_authenticationType": "AWS_IAM",
"aws_appsync_apiKey": "xxx-xxxxxxxxxxxxxxxxxxxxxxxxxx",
};
export default awsmobile;
In my App.js file I have attempted to get the identityPoolId to be used and I have created this:
Amplify.configure({
url: config.aws_appsync_graphqlEndpoint,
region: config.aws_appsync_region,
auth: {
type: config.aws_appsync_authenticationType,
apiKey: config.aws_appsync_apiKey,
region: 'eu-west-x',
identityPoolId: 'eu-west-x:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx',
}
})
When I use the app to read from DynamoDB I get this error
[WARN] 04:51.835 API - ensure credentials error, No Cognito Federated Identity pool provided
I then went back to the Cognito Manage Identity Pool page and changed my identity pool to use Cognito as an authentication source and provided a User Pool ID and an App client id. But I still get the same error.
I am fundamentally missunderstanding something, could you offer any insight?

How to integrate AWS Cognito Identity Pool and API Gateway in the Javascript sdk

I want to protect access to API Gateway using Cognito Identiy Pool (to which for now I authorize using Cognito User Pools, but later I may user other providers like facebook etc.)
So from the documentation here
AWS.config.credentials = new AWS.CognitoIdentityCredentials({
IdentityPoolId: 'YOUR_IDENTITY_POOL_ID',
Logins: {
'cognito-idp.<region>.amazonaws.com/<YOUR_USER_POOL_ID>': 'some-user-pool-token'
}
});
AWS.config.credentials.refresh((error) => {
...
}
But to use API Gateway (from an generated sdk) I need:
accessKey: 'ACCESS_KEY',
secretKey: 'SECRET_KEY'
My questions:
How do I get the ACCES_KEY and SECRET_KEY?
The only reason I need a dependency to the aws sdk is, that I need to call credentials.refresh. Can I somehow do this withpout the aws sdk (and only the amazon-cognito-identity-js as well as the generated api gateway sdk)?
The answer for 1 can be found here.
And it is done like this:
AWS.config.credentials = new AWS.CognitoIdentityCredentials({
IdentityPoolId: 'YOUR_IDENTITY_POOL_ID',
Logins: {
'cognito-idp.<region>.amazonaws.com/<YOUR_USER_POOL_ID>': 'some-user-pool-token'
}
});
AWS.config.credentials.get(function(){
// Credentials will be available when this function is called.
var accessKeyId = AWS.config.credentials.accessKeyId;
var secretAccessKey = AWS.config.credentials.secretAccessKey;
var sessionToken = AWS.config.credentials.sessionToken;
});
So I guess the answer to 2 is: Yes, one also needs the AWS SDK for getting the credentials.

Getting FB user's data from AWS "CognitoIdentityCredentials" using Facebook Login

Good day,
I've got an API setup, it's sitting behind AWS's APIGateway, secured with IAM, in this case it's a Cognito Federated ID pool.
I have the following code:
function doFacebookLogin() {
FB.login(function (response) {
fbAuthToken = response.authResponse.accessToken;
doFetchProfile();
}, {scope: 'public_profile,email', return_scopes: true});
}
function doFetchProfile() {
AWS.config.credentials = new AWS.CognitoIdentityCredentials({
IdentityPoolId: 'eu-west-1:*****************************',
Logins: {
'graph.facebook.com': fbAuthToken
}
});
// Obtain AWS credentials
AWS.config.credentials.get(function () {
apigClient = apigClientFactory.newClient({
accessKey: AWS.config.credentials.accessKeyId,
secretKey: AWS.config.credentials.secretAccessKey,
sessionToken: AWS.config.credentials.sessionToken,
region: 'eu-west-1'
});
apigClient.userProfileGet({
'x-fb-access-token': fbAuthToken
}).then(function (data) {
console.log(data);
});
});
}
Right now, I'm sending the Facebook AccessToken in the header, because my server (sitting behind the AWS APIGateway) needs access to the user's facebook profile data.
I was hoping that by simply signing into the Cognito Federated ID pool, using the Facebook provider, would be enough to have AWS's APIGateway SDK pass the accessToken (in some form or another) along with every request.
It doesn't seem to be the case, I can't find a way to extract the Facebook data I need without sending the AccessToken in the header as per the example above.
Am I wrong in my understanding of what should happen?
Thanks for the help in advance :)
If you're server behind API Gateway needs the Facebook access token to access some Facebook APIs, then yes you'll always need to pass the Facebook access token through in API GW.
The Cognito federated login allows you to exchange a Facebook token for AWS credentials for accessing AWS-protected services.

API gateway how to pass AWS IAM authorization from rest client

I am trying to test authenticated API gateway endpoint from rest client. How to I generate/set the "AWS_IAM" authorization headers when making the request ?
You can use Cognito with a "public" pool id, then attach role to the Cognito pool id, the role being accessing your API GATEWAY
AWS.config.credentials = new AWS.CognitoIdentityCredentials({
IdentityPoolId: 'REGION:YOUR_POOL_ID',
});
Use AWS STS to get temporary credentials with limited privileges. After that you can use API Gateway with AWS_IAM authentication
The generated SDK accepts AMI credentials, you have to initiate the client with the one you got from STS:
var apigClient = apigClientFactory.newClient({
accessKey: 'ACCESS_KEY',
secretKey: 'SECRET_KEY',
sessionToken: 'SESSION_TOKEN', //OPTIONAL: If you are using temporary credentials you must include the session token
region: 'eu-west-1' // OPTIONAL: The region where the API is deployed, by default this parameter is set to us-east-1
});
NB: Put strictly minimum roles on your pool, that is a publicly available id, every body can use it to get a temporary or a fixed (to track users across devices) user_/app_ id.
Update April 2016:
For Christine comment's: Documentation on how to use STS.
TL;DR: Basically after your Identity provider calls you back (Google, in my case), you will have a Token (OpenID, in my case), just feed it to STS:
AWS.config.credentials = new AWS.WebIdentityCredentials({
RoleArn: 'arn:aws:iam::<AWS_ACCOUNT_ID>:role/<WEB_IDENTITY_ROLE_NAME>',
ProviderId: 'graph.facebook.com|www.amazon.com', // Omit this for Google
WebIdentityToken: ACCESS_TOKEN
});
You'd have to replicate API Gateway AWS v4 request signature logic to be able to do that. Ideally you should look at the the generated Javascript/Java SDK for your API to get an idea on how these request signatures get calculated. I suggest you turn the authentication off for your testing requests.