AWS Cognito; unauthorized_client error when hitting /oauth2/token - amazon-web-services

Steps taken so far:
Set up new user pool in cognito
Generate an app client with no secret; let's call its id user_pool_client_id
Under the user pool client settings for user_pool_client_id check the "Cognito User Pool" box, add https://localhost as a callback and sign out url, check "Authorization Code Grant", "Implicit Grant" and everything under "Allowed OAuth Scopes"
Create a domain name; let's call it user_pool_domain
Create a new user with a username/password
Now, I can successfully go to:
https://{{user_pool_domain}}.auth.us-east-2.amazoncognito.com/oauth2/authorize?response_type=code&client_id={{user_pool_client_id}}&redirect_uri=https%3A%2F%2Flocalhost
This presents me with a login page and I am able to login as my user which returns me to https://localhost/?code={{code_uuid}}
I then try the following:
curl -X POST https://{{user_pool_domain}}.auth.us-east-2.amazoncognito.com/oauth2/token -H 'Content-Type: application/x-www-form-urlencoded' -d 'grant_type=authorization_code&redirect_uri=https%3A%2F%2Flocalhost&code={{code_uuid}}&client_id={{user_pool_client_id}}'
However, this just returns back the following:
{"error":"unauthorized_client"}
The token endpoint docs say that unauthorized_client is because "Client is not allowed for code grant flow or for refreshing tokens." which is confusing because I checked the boxes allowing the client to use the code grant flow.

So, it turns out that the user pool has to have a trailing slash (https://localhost/) and then that trailing slash has to be used in all of the callback URLs. Then it decides to work!

Everything looks OK to me. I think it may be complaining about the Authorization header missing but not sure. You could try a few things:
1) According to this page (https://docs.aws.amazon.com/cognito/latest/developerguide/token-endpoint.html), you shouldn't need to send the Authorization header in the token request, but maybe it is still needed. You could try either passing just the client ID in it (Authorization [client ID]) or configure a secret and try passing Authorization [client ID:client secret] like it says). It usually makes sense to use a client secret for authorization code flow anyway since in this flow, there is a server side component that can securely handle the token exchange.
2) Try using Implicit Flow instead to see if that works. Implicit Flow makes sense for single page apps with no server side component. For that, no client secret is needed.

If you are using amplify and have it configured outside of the CLI and the other answers aren't working for you, one last fix you can try is to ensure you have responseType: 'token' if you are using implicit flow. Fixed things for me.
Auth: {
oauth: {
domain : 'your-app.auth.your-region.amazoncognito.com',
redirectSignIn: environment.cognito.oauthCallbackLogin,
redirectSignOut: environment.cognito.oauthCallbackLogout,
responseType: 'token',
scope : ['email', 'openid', 'profile'],
}
}

I had this error for another reason: I had response_type=token in the request URL, but the implicit OAuth flow was not enabled in the user pool client, so I needed to change it to response_type=code.

I agree with #rioastamal and #kiran01bm
as well. I did not need a trailing slash and it has to be verbatim as configured for the callbacks.
In my case I had my Redirect URI encoded at definition like this const redirectUri = encodeURIComponent(REDIRECT_URI).
Later, when it was used in the POST call to the /token endpoint as part of the params, it resulted as a double-encoded string.
A facepalm moment, but could happen to anyone.
Getting rid of one of the encoding fixed it for me.

Make sure to also include the scope in the request. Like the following
https://domain.auth.eu-central-1.amazoncognito.com/signup?client_id={}&response_type=token&scope=aws.cognito.signin.user.admin+email+openid+phone+profile&redirect_uri=https://www.google.com/

I my case, the issue came from the ACS URL that was incorrect, but so close that I did not see it. It was redirecting my to a page with this error "An error was encountered with the requested page."

I configured the UserPoolClient via cloudformation and had the AllowOAuthFlows set to implicit, where to work with amplify/cognito I needed that value to be code.
GoogleUserPoolClient:
Type: AWS::Cognito::UserPoolClient
DependsOn: GoogleUserPoolIdentityProvider
Properties:
UserPoolId:!Ref MyUserPool
AllowedOAuthFlowsUserPoolClient: true
GenerateSecret: false
CallbackURLs:
- http://localhost:8080
LogoutURLs:
- http://localhost:8080
AllowedOAuthFlows:
- code
AllowedOAuthScopes:
- email
- openid
SupportedIdentityProviders:
- Google

Authorization code grant means you get a code at the end of that redirect and you have to exchange that code for the respective tokens, and the response Type will be code.
And the Implicit grant type is the equivalent of response type token, where in you will get the tokens on the first step itself.
So check if you have the correct response type as per your auth flow set in the cognito console.

In my case, I updated the localhost:port in Allowed callback URLs of cognito app client setting but failed to add localhost:port to Allowed sign-out URLs

Related

How to convert Amazon MWS credentials to SP-API creds

Here are the seemingly clear instructions from Amazon.
Simply send the following: sellingPartnerId, developerId, and mwsAuthToken
I do this with httparty like so:
query = {
sellingPartnerId: "A3Kxxxxx",
developerId: "753xxxx",
mwsAuthToken: "amzn.mws.8abxxxxx-xxxx-xxxx-xxxx-xxxxxx",
}
and then
send = HTTParty.get("https://sellingpartnerapi-na.amazon.com/authorization/v1/authorizationCode",
query: query
)
This returns the following error:
{"errors"=>
[{"message"=>"Access to requested resource is denied.",
"code"=>"MissingAuthenticationToken"}]}
I've adjusted the call everyway I've seen. I've read the following articles:
This
This
Paged through the 695 issues on github for this API and still no luck.. I've adjusted my query to this with no luck either:
query = {
grant_type: "client_credentials",
sellingPartnerId: "A3K98Oxxxxxx",
developerId: "753xxxxxxxx",
mwsAuthToken: "amzn.mws.8abxxxxxxx-xxxx-xxxx-xxxx-xxxxxxx",
client_id: "amzn1.application-oa2-client.xxxxxxxxxxxxxxxxxxxxxxxx",
client_secret: "a473e76XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
scope: "sellingpartnerapi::migration"
}
Nothing I've tried has worked.. Any suggestions? Has anyone actually migrated their MWS to SP-API credential successfully?
Unfortunately the specific Amazon docs that you link to don't tell the whole story. There are a few other requirements you'll need in order to get the authorizationCode response that you're looking for:
Amazon OAuth Token
You'll need an access token from Amazon's OAuth API (an entirely different API). You can use the grantless workflow for this, since in your case the user hasn't actually authorized the SP-API yet:
POST https://api.amazon.com/auth/o2/token
body: {
grant_type: 'client_credentials',
scope: 'sellingpartnerapi::migration',
client_id: 'amzn1.application-oa2-client.xxxxxxxxxxxxxxxxxxxxxxxx',
client_secret: 'a473e76XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
}
This will return an access_token that you'll need for your actual migration request to https://sellingpartnerapi-na.amazon.com/authorization/v1/authorizationCode. The response will look something like:
{
"access_token": "Atc|xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"scope": "sellingpartnerapi::migration",
"token_type": "bearer",
"expires_in": 3600
}
Important: Take the access_token value from that response and add it as an x-amz-access-token header to your /authorization/v1/authorizationCode request.
Sign Your Request
This is the actual reason behind the error you're receiving. An unsigned request will not include the "authorization token" that you're being prompted for.
You'll need to sign your request using Amazon's SigV4 signing mechanism. It looks like you're using Ruby (HTTParty), so you can use the aws-sdk's Aws::Sigv4::Signer for this. You'll need to have setup IAM credentials as documented in the generic developer guide, and those credentials being provided to your Aws::Sigv4::Signer somehow (hardcoding, env vars, Aws::SharedCredentials, etc.)
Request signing will result in a few proprietary headers being added to your request. Once this is done, you should have all that you need to make the request successfully.

Alexa Request Customer contact Access Denied

I am observing a very weird behavior in Requesting Customer Contact information, email in my skill's case.
I have implemented the exact same way as mentioned in the documentation. I have provided the permission in the skill's permission tab (for email). I have granted the permission in the app and from the code, I am calling the following REST API for fetching email id of the user by passing Bearer token (consent token in permissions object received in JSON input)
https://api.eu.amazonalexa.com/v2/accounts/~current/settings/Profile.email
But the weird thing is, that recently, I am getting this response
{'code': 'ACCESS_DENIED', 'message': 'Authentication failure with
reason: TOKEN_INVALID'}
I have been recently facing this issue that sometimes the API is working fine but sometimes, it is not and I am receiving the above errors.
Can anyone help please?
I am calling the following REST API for fetching email id of the user
by passing Bearer token (consent token in permissions object received
in JSON input)
According to this doc, consentToken has been deprecated, you should use apiAccessToken instead.
Important: Requests from Alexa may also include a consentToken within
session.user.permissions and context.System.user.permissions. This
property is deprecated. Existing skills that use consentToken continue
to work, but the context.System.apiAccessToken property should be used
instead.
Thus, accessToken = this.event.context.System.apiAccessToken.
Also, double-check your header: {"Authorization": "Bearer " + apiAccessToken}, make sure you have a space between Bearer and apiAccessToken.

How can I get a response when calling Slack's oauth/authorize?

When I try to make the following call using postman I get no response: https://slack.com/oauth/authorize?client_id={{client id}}&scope=chat:write:bot
However, when I try it without the scope I do get a response, saying I need to add a scope.
I've put this call together according to the first step of https://api.slack.com/docs/oauth
I've tried using both GET and POST verbs and my header is empty.
What can I do to get a authorization token for Slack?
This is part of the OAuth flow/spec.
What you need to do to is follow/perform the OAuth flow:
Register your application with slack
Provide a redirect_uri - this is the callback URI - this callback/handler will be called with the authenticationCode by the slack OAuth server.
Only if the user authorizes your app, Slack will redirect back to your specified redirect_uri with a temporary code in a code GET parameter, as well as a state parameter if you provided one in the previous step.
It's true that the redirect url is optional, but if left out, Slack will redirect users to the callback URL configured in your app's settings.
the authenticationCode then needs to be changed in code to the accessToken.
So if all is well and user gave its consent, you need to exchange the authorization code for an access token using the OAuth.access API method (method documentation), int the following URL and retrieve your accessToken.
https://slack.com/api/oauth.access
if you decide to use a bot user and your Slack app includes a bot user, you will get an additional node containing an access token to be specifically used for your bot user.

WSO2 Implicit Flow not returning id_token

I am trying to authenticate a user from a custom web app with an OpenID Connect Service Provider within WSO2. I am following an answer on this article and added the Nuget package Thinktecture.IdentityModel.Client. My code is very similar to the linked article:
var client = new OAuth2Client(new Uri(serviceProviderAuthorizeUrl));
var url = client.CreateImplicitFlowUrl(
clientId,
redirectUri: redirectUrl,
scope: scope,
nonce: Guid.NewGuid().ToString());
Response.Redirect(url);
The url comes out to be: https://{wso2_url}/oauth2/authorize?client_id={my_client_id}&response_type=token&scope=openid&redirect_uri=https%3A%2F%2F{mydomain}%2F{my_app}%2FCallback.aspx&nonce=f0db4eac-18df-46f6-92f1-c28ba621596d
Now this does work and returns an access_token: https://{my_domain}/{my_app}/Callback.aspx#token_type=Bearer&expires_in=970&access_token=067e3366217798986912326a86abd92f
My issue is that I have no idea who the user is. Further more, this WSO2 article shows that if I pass a response_type:id_token I should be able to decode the response and find out who the user is by using the "sub" attribute but I am not getting the id_token response. The code above creates a url with a response_type of token instead. Simply changing the response_type gives me an error. How can I use implicit flow in WSO2 and get the id_token response?
I followed this article for the configuration of WSO2. I currently have Implicit and Client Credential checked.
Make sure you have these as query parameters.
response_type=id_token
client_id=xxxxx
redirect_uri=http://xx.com/xx/x
nonce=xxxx
scope=openid
Make sure that you pass on the scope intended to use for the Idp (WSO2) to know what data it needs to return. Make sure your scop
scope=openid.

Missing Authentication Token while accessing API Gateway?

I am trying to call a Lambda Function through AWS API Gateway.
When I mention Authentication type NONE it works fine but API become public and anyone with url can access my API.
To make API call secure, I am using Authentication type AWS_IAM and
also attached AmazonAPIGatewayInvokeFullAccess policy to my user but getting this error:
{ message: "Missing Authentication Token"}
I don't know what I am missing here.
I've lost some time for a silly reason:
When you create a stage, the link displayed does not contain the resource part of the URL:
API URL:
https://1111.execute-api.us-east-1.amazonaws.com/dev
API + RESOURCE URL
https://1111.execute-api.us-east-1.amazonaws.com/dev/get-list
The /get-list was missing
And of course, you need to check that the method configuration looks like this:
I think you are directly trying to access API link, this won't work because API is secured using IAM role and you must provide AWS authentication i.e Access key and Secret key.
Use the Postman Chrome extension to test your API:
http://docs.aws.amazon.com/apigateway/latest/developerguide/how-to-use-postman-to-call-api.html
I just had the same issue and it seems it also shows this message if the resource cannot be found.
In my case I had updated the API, but forgotten to redeploy. The issue was resolved after deploying the updated API to my stage.
Make sure you are clicking on the specific Resource first in the Stages tree, as that will populate a URL with the full path to the resource (rather than just the root path):
For other causes, see http://www.awslessons.com/2017/aws-api-gateway-missing-authentication-token/
Looks like (as of April 2019) AWS API Gateway throws this exception for a variety of reasons - mostly when you are hitting an endpoint that API Gateway is not able to reach, either because it is not deployed, or also in cases where that particular HTTP method is not supported.
I wish the gateway sends more appropriate error codes like HTTP 405 Method not supported or HTTP 404 not found, instead of a generic HTTP 403 Forbidden.
Found this in the docs:
If the AWS_IAM authorization were used, you would sign the request using the Signature Version 4 protocols.
Signing request with Signature Version 4
You can also generate an SDK for your API.
How to generate an SDK for an API in API Gateway
Once you've generated the SDK for the platform of your choice, step 6 mentions that if you're using AWS credentials, the request to the API will be signed:
To initialize the API Gateway-generated SDK with AWS credentials, use code similar to the following. If you use AWS credentials, all requests to the API will be signed. This means you must set the appropriate CORS Accept headers for each request:
var apigClient = apigClientFactory.newClient({
accessKey: 'ACCESS_KEY',
secretKey: 'SECRET_KEY',
});
I try all the above, if you did all steps in the above answers, and you not solve the problem, then:
on the left menu, hit the "Resources"
in the right to "Resources", hit the api method that you want to test, like "POST/GET etc)
hit the "ACTION" list (it's above to the API method in step 2
select "DEPLOY API" (please do it, even you already deploy yours api)
in "deployment stage" select "prod" or what ever you write in yours previous deploy (it will override yours previous deploy
hit deploy
I thing that because of, when I create the "METHOD REQUEST" (see step 2 how to go to this menu) , in "Authorization" I select "AWS_IAM"
after testing api, in aws test option, I try it in "postman"
then I understand the in "METHOD REQUEST" , in "Authorization", I should select "none"
I change it to none, but I thing the AWS, need to deploy it again, as I explain
Make sure you create Resource and then create method inside it. That was the issue for me. Thanks
In my case I missed adding '/' forward slash at the end of api.
Such a silly mistake.
https://le9dq5l9.execute-api.eu-west-1.amazonaws.com/v1/putdoctorinfo/
If you enable AWS_IAM authentication you must sign your request with AWS credentials using AWS Signature Version 4.
Note: signing into the AWS console does not automatically sign your browser's requests to your API.
sometimes this message shown when you are calling a wrong api
check your api endpoint
In my case it was quite a stupid thing.
I've get used that new entities are created using POST and it was failing with "Missing Authentication Token". I've missed that for some reason it was defined as PUT which is working fine.
This error mostly come when you call wrong api end point.
Check your api end point that you are calling and verify this on api gateway.
If you are using an API with endpoint of type PRIVATE, be sure of:
You are invoking the API from within your AWS account (example: from an EC2 instance created in your account)
Put necessary credential (access and secret keys) in the EC2 instance in route ~/.aws/credentials (this route is for linux instances) If IAM user use MFA aws_session_token value will be required too.
Use vpce (vpc endpoint) based URL. Example: curl https://vpce-0c0471b7test-jkznizi5.execute-api.us-east-1.vpce.amazonaws.com/dev/api/v1/status
Your EC2 instance have a security group than allow outbound traffic to another security group owned by the vpce like:
Your vpce security group allow inbound traffic from another security group (previous sg from ec2 instance) owned by the EC2 instance like:
See: https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-private-apis.html
I had the same problem which I solved the following way:
GET Method test
https://54wtstq8d2.execute-api.ap-southeast-2.amazonaws.com/dev/echo/hello
Authorization tab ->
• select type(AWS signature)
• Add AccessKey and SecretKey
You must be using Invoke Url to trigger Lambda Function from your browser or POSTMAN... Instead, use the API end point which will be listed in:
select yourLambdaFuntion >> Configuration >> Triggers.
There you can see API end point.
For the record, if you wouldn't be using credentials, this error also shows when you are setting the request validator in your POST/PUT method to "validate body, query string parameters and HEADERS", or the other option "validate query string parameters and HEADERS"....in that case it will look for the credentials on the header and reject the request. To sum it up, if you don't intend to send credentials and want to keep it open you should not set that option in request validator(set it to either NONE or to validate body)
I had the same issue, and fixed it by removing the /dev/ and just put: https://1111.execute-api.us-east-1.amazonaws.com/get-list
I had same issue today because I was using GET instead of POST. Fixed the issues by changing method to POST in postman.
First of all, check whether the API you created in the lamda function is registered with your AWS project or not. For that, go to the API gateway in your AWS console. If it is not registered, register it. This is the main cause of this issue.
You can even see in your aws.export.js file, that there are paths corresponding to your API ['/items'].
Your API must be present there, otherwise it will not append the security token to requests. Just register it in your project cloud-logic in your console for this.
If it's there, then use the above mentioned solution
http://docs.aws.amazon.com/apigateway/latest/developerguide/how-to-use-postman-to-call-api.html
To contribute:
I had a similar error because my return response did not contain the 'body' like this:
return {
'statusCode': 200,
'body': "must contain the body tag if you replace it won't work"
}
If you set up an IAM role for your server that has the AmazonAPIGatewayInvokeFullAccess permission, you still need to pass headers on each request. You can do this in python with the aws-requests-auth library like so:
import requests
from aws_requests_auth.boto_utils import BotoAWSRequestsAuth
auth = BotoAWSRequestsAuth(
aws_host="API_ID.execute-api.us-east-1.amazonaws.com",
aws_region="us-east-1",
aws_service="execute-api"
)
response = requests.get("https://API_ID.execute-api.us-east-1.amazonaws.com/STAGE/RESOURCE", auth=auth)
Well for anyone still having the problem and I really feel very dumb after realizing this, but I passed in the url of /items the default one while adding API. But I kept calling the endpoint with /api. Special thanks to Carlos Alberto Schneider, as I realized my problem after reading your post.
According to my experience, please check the following steps:
On API gateway side, make sure you add the correct path and publish the resource at the stage you want. For some url pattern like path parameter(/user/{user_id}) need more attention to have a check.
Make sure you configure the correct options method for this resource, because sometimes it is the CORS that cause this problem.
On Lambda side, make sure you specify the correct handler name as the entrypoint.
Please always check cloudwatch logs of your lambda that can help u identify the problems on your lambda side.
In my case I was trying to do an UPDATE type request but in my AWS SAM template I had a PATCH type request:
Resources:
LambdaFunction:
Type: AWS::Serverless::Function # More info about Function Resource:
# https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#awsserverlessfunction
Properties:
CodeUri: src/
Handler: app.lambda_handler
Runtime: python3.8
MemorySize: 128
Events:
UpdateItem:
Type: Api
Properties:
Path: /my-endpoint
Method: patch
Things to check:
1. In resources, check for Authorization and API Key if these are required.
2. Redeploy the API, new changes might not reflected.
3. Get the url from stages, directly by clicking on the actions like GET, POST, These will contain the full path urls.
I had the same issue even if my access was regional and not private, no authorization on my method neither API. It's turned out that I was calling the root endpoint "https://azerty.execute-api.eu-west-3.amazonaws.com/dev/", which in local return me a json but raised an error. Be sure to call a proper endpoint, such as "https://azerty.execute-api.eu-west-3.amazonaws.com/dev/hello"