"Missing Authentication Token" when using the AWS apigclient (with credentials) - javascript

Update
I resolved this by removing the old pool and creating a new one. I believe the problem was in the end wrongly configured cognito roles. It works as expected now.
I'm having some issues with the API Gateway client (Javascript/Browser) when trying to access an protected lambda (Authorization : AWS_IAM) via the API Gateway.
The problem is that I keep getting "Missing Authentication Token" when calling the resource via the apiClient for my API Gateway.
I'm following the "enhanced flow" under Developer Authenticated Identities Authflow ref: http://docs.aws.amazon.com/cognito/latest/developerguide/authentication-flow.html?shortFooter=true
Is it possible to protect lambdas like this at all, or do I have to use an authorizer for my case? I was under the impression that my temporary credentials from cognito could be used as a IAM for the duration, but it could explain a lot. I have an authorizer planned for later - for protecting other resources.
The actual call to the lambda is like this:
var params = {};
var body = {
message: vm.message
};
var additionalParams = {
headers: {},
queryParams: {}
};
var apiClient = apigClientFactory.newClient( {
accessKey : data.awstoken.AccessKeyId,
secretKey : data.awstoken.SecretAccessKey,
sessionToken : data.awstoken.SessionToken,
region : Config.aws.region
});
apiClient.testEchoPost( params, body, additionalParams )
.then( function ( result ) {
console.info( 'TEST_RESULT', result );
})
.catch( function ( error ) {
console.error( 'dang', error );
});
}

Forgot to answer correctly. I had to recreate the pool (could probably have fixed the roles instead), after that the thing woked up and I could protect the resource with AWS_IAM.

Related

How do I make authenticated requests to Amplify GraphQL using Firebase Auth as OIDC?

I need help setting up Firebase Auth + Amplify GraphQL. I'm trying to log in using federated sign with securetoken.google.com/PROJECT-ID as the provider, and it seems to log in alright because when I call Auth.currentAuthenticatedUser() I get the token, and when listening to Hub "signIn" event I get the token. My problem is making authenticated requests to my GraphQL API.
const signIn = async () => {
try {
// already logged in using firebase so I just need to get the token from the current user
const tokenResult = await currentUser?.getIdTokenResult()
await Auth.federatedSignIn('securetoken.google.com/PROJECT-ID', {
token: tokenResult?.token,
})
const res = await Auth.currentAuthenticatedUser()
console.log('token', res.token) // eyjhxxxxxxxxxx...
} catch (error) {
// ...
}
}
const client = new AWSAppSyncClient({
url: AppSyncConfig.aws_appsync_graphqlEndpoint,
region: AppSyncConfig.aws_appsync_region,
auth: {
type: AppSyncConfig.aws_appsync_authenticationType,
jwtToken: () => getToken(),
},
})
const getToken = async () => {
const token = await Cache.getItem('#accessToken')
return token
}
When calling Auth.currentSession() I get "No current user". Also, I do see the token in the Authorization header when I attempt to fetch data.
I have had a similar issue so here are some things you can have a look at.
In the Appsync in the AWS Console
https://eu-west-1.console.aws.amazon.com/appsync/home
Make sure that your primary authorization mode is set to Open Id Connect, or add another authorization provider specifying "OpenId Connect" if you are happy with the primary.
If that does not solve it, you can try to add the #aws_oidc AppSync directive to your GraphQL schema.
type Query {
getPosts:[Post!]! #aws_oidc
}
or
type Post
#model
#auth(
rules: [
{ allow: owner, provider: oidc }
...
more here: https://aws.amazon.com/blogs/mobile/graphql-security-appsync-amplify/
Lastly, if you have more than one authorization provider, you might have to switch the primary authorization provider to "OpenId Connect" - the issue I had was that Cognito (primary) blocked my secondary API Key authorization provider.
Update
AWS uses IAM roles for everything related to security. So when you authenticate with whichever authentication provider an IAM role will be assigned to that request, and that IAM role needs permission on the resource in question, like execute permission on GraphQL queries, scanning of DynamoDB tables etc. as per this image:
So you might need specific rules set in the IAM console for the IAM role in question - or at least check that it has permission - if not, you'll also get an unauthorized error message in the Appsync GraphQL query console.
more here: https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/WIF.html?icmpid=docs_ddb_console
and here: https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/specifying-conditions.html?icmpid=docs_ddb_console
Try removing the cookie storage configuration in aws-exports.js may solve it. Maybe this helps you.
More discussion here Link-1 and Link-2

Using appUser scoped tokens in Smooch

I am developing a widget that users in my company can use to communicate with end-users through Smooch.
The widget is accessible through the web browser and the communication goes mostly through a layer developed in node. However, I was trying to send attachments directly to Smooch to reduce the load in the server.
As I understand, it is necessary to use a token with a appUser scope to avoid issues with CORS.
I create the token using the following code
app.get('/getjwt', (req, res) => {
var token = jwt.sign({ scope: 'appUser', userId: req.body.userId }, SECRET, { header: { 'alg': 'HS256', 'type': 'JWT', 'kid': '[app key ID]' } });
res.send({ jwt: token });
});
I try to use the generated token (using Postman for tests) by making a request with Authorization Bearer [my generated token] and I get the following error:
{
"error": {
"code": "invalid_auth",
"description": "Invalid JWT header. Missing key id (kid)"
}
}
I have tried changing the 'kid' value to the app ID, the API key ID, and the API key Secret and I'm always getting the same error. What am I missing? Am I supposed to pass the Key ID somewhere else?
Thank you,
Your code works fine for me, what version of jsonwebtoken are you using? In v6.0.0 the headers option was renamed to header, so if you're using 5.x or lower your code should look like this instead
var token = jwt.sign({ scope: 'appUser', userId: req.body.userId }, SECRET, { headers: { 'alg': 'HS256', 'type': 'JWT', 'kid': '[app key ID]' } });
That said, Smooch already provides a fully functional web messenger / widget that you should use instead of attempting to build your own. It provides event hooks and methods to build a fully custom UI if that's what you're trying to achieve. See https://docs.smooch.io/guide/web-messenger/ and https://www.npmjs.com/package/smooch

instafeed.js stopped working: The access_token provided is invalid

I am using instafeed.js like so:
var feed = new Instafeed({
get: 'user',
userId: 19191919191,
limit: 9,
accessToken: 'myaccesstokenhere',
target: 'instagram',
resolution: 'standard_resolution',
after: function() {
var el = document.getElementById('instagram');
if (el.classList)
el.classList.add('show');
else
el.className += ' ' + 'show';
}
});
but I am getting this error:
The access_token provided is invalid.
I got the access_token by https://www.instagram.com/developer I registered my application and put the Client Secret as the accessToken and I got my userID from here https://smashballoon.com/instagram-feed/find-instagram-user-id/
but its still saying The access_token provided is invalid. what am I doing wrong?
You cannot use your Client Secret in place of accessToken, as the Client Secret is used server-side as part of the OAuth process in order to get the user accessToken.
I suggest reviewing Instagram's Authentication docs here to be sure you're using the Authentication strategy that makes sense for your application.
It sounds like you're more likely to want to use their Client Side Implicit Authentication (at the bottom) to get an access token. You can even do this yourself manually to just get an accessToken for testing. Once you have the accessToken, then you can simply use that in the correct field for instafeed.js to load what you want from Instagram.
You can also just get your own accessToken by going to http://instagram.pixelunion.net/ and using the one generated there.
Seems you confused accessToken with Client Secret, check it here https://www.instagram.com/developer/authentication/
To make life easy you can try to generate one here http://instagram.pixelunion.net/

Unable to query Google Search Console API using a Service Account

I need to retrieve some data from Google Search Console (Webmaster Tools) using a service account.
So far I've been able to retrieve an access_token for the service account which I need to append to the url of the request. The problem is that I can't find a way to do so, this is the code i'm using:
function retrieveSearchesByQuery(token)
{
gapi.client.webmasters.searchanalytics.query(
{
'access_token': token,
'siteUrl': 'http://www.WEBSITE.com',
'fields': 'responseAggregationType,rows',
'resource': {
'startDate': formatDate(cSDate),
'endDate': formatDate(cEDate),
'dimensions': [
'date'
]
}
})
.then(function(response) {
console.log(response);
})
.then(null, function(err) {
console.log(err);
});
}
This is the url called by the function:
https://content.googleapis.com/webmasters/v3/sites/http%3A%2F%2Fwww.WEBSITE.com/searchAnalytics/query?fields=responseAggregationType%2Crows&alt=json"
Instead it should be something like this:
https://content.googleapis.com/webmasters/v3/sites/http%3A%2F%2Fwww.WEBSITE.com/searchAnalytics/query?fields=responseAggregationType%2Crows&alt=json&access_token=XXX"
The gapi.client.webmasters.searchanalytics.query doesn't recognize 'access_token' as a valid key thus it doesn't append it to the url and that's why I get a 401 Unauthorized as response.
If I use 'key' instead of 'access_token' the parameter gets appended to the url but 'key' is used for OAuth2 authentication so the service account token I pass is not valid.
Does anyone have a solution or a workaround for this?
If your application requests private data, the request must be authorized by an authenticated user who has access to that data. As specified in the documentation of the Search Console API, your application must use OAuth 2.0 to authorize requests. No other authorization protocols are supported.
If you application is correctly configured, when using the Google API, an authenticated request looks exactly like an unauthenticated request. As stated in the documentation, if the application has received an OAuth 2.0 token, the JavaScript client library includes it in the request automatically.
You're mentioning that you have retrieved an access_token, if correctly received, the API client will automatically send this token for you, you don't have to append it yourself.
A very basic workflow to authenticate and once authenticated, send a request would looks like the following code. The Search Console API can use the following scopes: https://www.googleapis.com/auth/webmasters and https://www.googleapis.com/auth/webmasters.readonly.
var clientId = 'YOUR CLIENT ID';
var apiKey = 'YOUR API KEY';
var scopes = 'https://www.googleapis.com/auth/webmasters';
function auth() {
// Set the API key.
gapi.client.setApiKey(apiKey);
// Start the auth process using our client ID & the required scopes.
gapi.auth2.init({
client_id: clientId,
scope: scopes
})
.then(function () {
// We're authenticated, let's go...
// Load the webmasters API, then query the API
gapi.client.load('webmasters', 'v3')
.then(retrieveSearchesByQuery);
});
}
// Load the API client and auth library
gapi.load('client:auth2', auth);
At this point, your retrieveSearchesByQuery function will need to be modified since it doesn't need to get a token by argument anymore in order to pass it in the query. The JavaScript client library should include it in the request automatically.
You can also use the API Explorer to check what parameters are supported for a specific query and check the associated request.
If you need to use an externally generated access token, which should be the case with a Service Account, you need to use the gapi.auth.setToken method to sets the OAuth 2.0 token object yourself for the application:
gapi.auth.setToken(token_Object);

How do I use Cognito with the generated Javascript SDK?

I couldn't find any documentation that showed how to do this so I tried my best to figure it out (is this not a common use case)? I've set up my resource to use IAM authentication, set up CORS, etc. Then I deployed it, and downloaded the generated the SDK.
On the client-side I'm using the credentials from AWS.CognitoIdentityCredentials with apigClientFactory.newClient. When I try to post to my resource, I get a 403 error response with no body.
The response headers contain: x-amz-ErrorType: UnrecognizedClientException
Could this error possibly be coming from some other AWS service (do they bubble up like that)? If so, how can I tell which one? What else might be causing the error?
The code I'm using test test client-side looks like this:
function onFacebookLogin(fbtoken) {
// get cognito credentials
AWS.config.credentials = new AWS.CognitoIdentityCredentials({
IdentityPoolId: 'us-east-1:abcd6789-1234-567a-b123-12ab34cd56ef',
Logins: {'graph.facebook.com': fbtoken}
});
AWS.config.credentials.get(function(err) {
if (err) {return console.error('Credentials error: ', err);}
/* I'm assuming that this is what I use for accessKey and secretKey */
var credentials = AWS.config.credentials;
apigClient = apigClientFactory.newClient({
accessKey: credentials.accessKeyId,
secretKey: credentials.secretAccessKey
});
});
}
I think what might be happening is you're not setting the sessionToken field with the access key and secret key. Can you try setting it up to look like the below example and see if that works?
var client = apigClientFactory.newClient({
accessKey: ACCESS_KEY,
secretKey: SECRET_KEY,
sessionToken: SESSION_TOKEN
});
This previous question has a bit more detail, if needed.
Yes I believe the sessionToken is required.
Here's a basic example using cognito unauthenticated identities: https://github.com/rpgreen/aws-recipes/blob/master/app/index.html

Categories