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.
Related
I am requesting access token from Microsoft Graph using this procedure:
I request access to the following scopes:
User.Read.All openid profile email offline_access https://outlook.office.com/IMAP.AccessAsUser.All https://outlook.office.com/POP.AccessAsUser.All https://outlook.office.com/SMTP.Send
After the consent screen in web browser, the redirection occurs and the codes are sent to temporary localhost web server running on user's PC.
The code received is exchanged for access_token and refresh_token
When I try to query Microsoft Graph for user's profile I query:
GET https://graph.microsoft.com/v1.0/me
Header of the GET request contains:
Authorization: Bearer token-here-all-in-one-line
But I get the resulting JSON:
"InvalidAuthenticationToken"
"CompactToken parsing failed with error code: 8004920A"
I would normally assume the token is not correct, but I tested the same token from C++ app and a small PHP app, and I always test the same error. To be sure that it is not the wrong token, I deliberately modify it to a wrong token and then I get:
"CompactToken parsing failed with error code: 80049217"
After googling - 8004920A means "token rejected" (the error I have problem with) and 80049217 means "malformed token" so that is consistent with me deliberately inserting false data as token.
So I would assume that the token is correct but Microsoft Graph rejects it to query user profile information which is consented and approved.
I have tested the token on IMAP and SMTP access and there it works - mails are sent and received, so the access_token is definitely good.
Any ideas why Microsoft Graph rejects my attempt to query user profile?
Do I need to enable something when registering application in AzureAD portal?
I am doing this from C++ or from PHP so I don't think the code is of relevance here.
Not sure if this is the case, but it may be. You cannot use the same token for graph access and another API acccess (such as Outlook REST api, in your case). Meaning, you cannot mix scopes from different namespaces. Not sure why ("by design"?), you just can't. You need two separate tokens.
I faced similar issue with SharePoint REST api access (so may not be 100% sure it is also true for Outlook as well, but probably it is). I used a relatively easy way out - exchanging the token requested for openid profile email offline_access for token for https://outlook.office.com/... on my server (using the on_behalf_of flow).
If you don't really need the graph scope User.Read.All you could also try simply removing that one from your first authorization call that obtains the token.
As #Nikolay has stated, the tokens for Graph and Outlook can't be mixed. And Microsoft has designed it poorly so that IMAP.AccessAsUser.All for example can't be used for IMAP access - the access_token simply won't work unless the https://outlook.office.com/ prefix is added.
But - I found another way, which works for just reading the user's profile and email address which is by decoding the id_token. As Microsoft documentation states - openid profile and email scopes will work with both Graph and Outlook. profile token can be used to extract the information about user's profile.
As explained on:
https://learn.microsoft.com/en-us/azure/active-directory/develop/id-tokens
id_token contains information such as email address, name etc.
A sample ID token from their page is:
eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6IjFMVE16YWtpaGlSbGFfOHoyQkVKVlhlV01xbyJ9.eyJ2ZXIiOiIyLjAiLCJpc3MiOiJodHRwczovL2xvZ2luLm1pY3Jvc29mdG9ubGluZS5jb20vOTEyMjA0MGQtNmM2Ny00YzViLWIxMTItMzZhMzA0YjY2ZGFkL3YyLjAiLCJzdWIiOiJBQUFBQUFBQUFBQUFBQUFBQUFBQUFJa3pxRlZyU2FTYUZIeTc4MmJidGFRIiwiYXVkIjoiNmNiMDQwMTgtYTNmNS00NmE3LWI5OTUtOTQwYzc4ZjVhZWYzIiwiZXhwIjoxNTM2MzYxNDExLCJpYXQiOjE1MzYyNzQ3MTEsIm5iZiI6MTUzNjI3NDcxMSwibmFtZSI6IkFiZSBMaW5jb2xuIiwicHJlZmVycmVkX3VzZXJuYW1lIjoiQWJlTGlAbWljcm9zb2Z0LmNvbSIsIm9pZCI6IjAwMDAwMDAwLTAwMDAtMDAwMC02NmYzLTMzMzJlY2E3ZWE4MSIsInRpZCI6IjkxMjIwNDBkLTZjNjctNGM1Yi1iMTEyLTM2YTMwNGI2NmRhZCIsIm5vbmNlIjoiMTIzNTIzIiwiYWlvIjoiRGYyVVZYTDFpeCFsTUNXTVNPSkJjRmF0emNHZnZGR2hqS3Y4cTVnMHg3MzJkUjVNQjVCaXN2R1FPN1lXQnlqZDhpUURMcSFlR2JJRGFreXA1bW5PcmNkcUhlWVNubHRlcFFtUnA2QUlaOGpZIn0.1AFWW-Ck5nROwSlltm7GzZvDwUkqvhSQpm55TQsmVo9Y59cLhRXpvB8n-55HCr9Z6G_31_UbeUkoz612I2j_Sm9FFShSDDjoaLQr54CreGIJvjtmS3EkK9a7SJBbcpL1MpUtlfygow39tFjY7EVNW9plWUvRrTgVk7lYLprvfzw-CIqw3gHC-T7IK_m_xkr08INERBtaecwhTeN4chPC4W3jdmw_lIxzC48YoQ0dB1L9-ImX98Egypfrlbm0IBL5spFzL6JDZIRRJOu8vecJvj1mq-IUhGt0MacxX8jdxYLP-KUu2d9MbNKpCKJuZ7p8gwTL5B7NlUdh_dmSviPWrw
The token consists of 3 parts - header, payload and the signature. They are separated by a dot. That's a standard JWT (JSON Web Token) See details at - https://en.wikipedia.org/wiki/JSON_Web_Token
After separating them and then base64 decoding each (the signature doesn't give anything useful after decoding) the result is:
1) The header
{
"typ": "JWT",
"alg": "RS256",
"kid": "1LTMzakihiRla_8z2BEJVXeWMqo"
}
2) The payload
Payload which contains the user info. Additional information can be extracted by adding Optional claims when registering app in Azure AD - (Token configuration in the menu on the left).
{
"ver": "2.0",
"iss": "https://login.microsoftonline.com/9122040d-6c67-4c5b-b112-36a304b66dad/v2.0",
"sub": "AAAAAAAAAAAAAAAAAAAAAIkzqFVrSaSaFHy782bbtaQ",
"aud": "6cb04018-a3f5-46a7-b995-940c78f5aef3",
"exp": 1536361411,
"iat": 1536274711,
"nbf": 1536274711,
"name": "Abe Lincoln",
"preferred_username": "AbeLi#microsoft.com",
"oid": "00000000-0000-0000-66f3-3332eca7ea81",
"tid": "9122040d-6c67-4c5b-b112-36a304b66dad",
"nonce": "123523",
"aio": "Df2UVXL1ix!lMCWMSOJBcFatzcGfvFGhjKv8q5g0x732dR5MB5BisvGQO7YWByjd8iQDLq!eGbIDakyp5mnOrcdqHeYSnltepQmRp6AIZ8jY"
}
3) The signature
For verification purposes only.
1AFWW-Ck5nROwSlltm7GzZvDwUkqvhSQpm55TQsmVo9Y59cLhRXpvB8n-55HCr9Z6G_31_UbeUkoz612I2j_Sm9FFShSDDjoaLQr54CreGIJvjtmS3EkK9a7SJBbcpL1MpUtlfygow39tFjY7EVNW9plWUvRrTgVk7lYLprvfzw-CIqw3gHC-T7IK_m_xkr08INERBtaecwhTeN4chPC4W3jdmw_lIxzC48YoQ0dB1L9-ImX98Egypfrlbm0IBL5spFzL6JDZIRRJOu8vecJvj1mq-IUhGt0MacxX8jdxYLP-KUu2d9MbNKpCKJuZ7p8gwTL5B7NlUdh_dmSviPWrw
So I've been trying to use Djoser JWT and I don't know how to login in it. As far as I know you create a request with your login credentials to this url /jwt/create/ and get the access and refresh token and maybe get the user object from /users/me/. This is where I got stuck, where do I go from here?
You correctly understood the first step of the process. Basically, you can now:
Add the access token in the header of your next requests.
This will transparently authenticate the user thanks to the Simple JWT plugin and you will be able to access him with the usual request.user in the views.
Refresh the access token each time you get a 401 response.
The access token is supposed to be short-living for security concerns and a 401 response from the server indicates that the one your are using is expired. So you have to get a new one by sending the refresh token to the token/refresh/ API and, then, make your request again.
You can read this article if you need more detailed explanations about this process or JWT.
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
I'm using Amazon Cognito for authorization of my app.
I'm using the authorization code flow. I can successfully get my token on /oauth2/authorize?...
But I can't seem to successfully get access_token, id_token and refresh_token using the POST to /oauth2/token with the Content type header: application/x-www-form-urlencoded
and body:
{"key":"grant_type","value":"authorization_code"},
{"key":"client_id","value":"xyz"},
{"key":"redirect_uri","value":"redirect-url.com"},
{"key":"code","value":"code_from_previous_request"}
When I make this call I get the following error json:
{"error":"invalid_request"}
Client id is correct and client app has no secret.
Anyone has any idea what I'm doing wrong?
By taking a closer look a #MikePatrick's request I figured it out. I was sending a wrong parameter
redirect_url
instead of
redirect_uri
...
Note to self: Half of software bugs are caused by typos
This is a problem we are confronted with today. I looked online as much as I can before deciding to ask the question here.
The question is, when a user makes a "Access Token Request" with a username/password, should the Access Token response contain "user-id" field?
The OAuth 2.0 spec says there can be an extra field (search for "example_parameter" in the spec) as part of the access token response. Can this extra field be user-id?
However, Many of the companies like facebook/google/twitter does not provide user-id as part of the access token response. User-id is provided as part of the validate token response.
What are the reasons for not providing user-id as part of the Access Token response? Why do we have to make another call (an extra round trip) if we need a user-id? What are the consequences of providing user-id as part of the Access Token response?
Most applications don't want to leak their user-ids to the UI layer. It is generally considered bad practice. If you send the userid to the UI layer, the UI will have the ability to request information about that UserId, and get information about it back...
This presents a security issue, as the client can generally modify these calls to get information about other UserIDs... If you are going to authenticate each call each time to validate that the token is bound to that user id, then it likely is a waste to have the client pass the userid itself, you are already doing the lookup, so you might as well keep the data internal to the service.
This also sets you up nicely to change your concept of a UserId in the future, maybe changing it to be group id, or an email address instead of the database userid...
Oauth2.0 is an authorisation framework and doesn't deal with user authentication.
The question is, when a user makes a "Access Token Request" with a
username/password, should the Access Token response contain "user-id"
field? In this context the resource
It's really a client requesting an access token and in many cases a client doesn't want to know about the id of the resource owner it just wants a token to allow it it call an endpoint on the resource server. The resource server can identity the user from the contents of the access token.
OpenID Connect can be used to extend OAuth2.0 to include an ID token. This gives basic user info in a standard format without the need to call a further endpoint.
An access token is a normally a bearer token that allows you to call an API. In OpenID Connect, you use the access token to call an api called the user_info endpoint, which returns a JSON object that contains information about the person, like first name, last name, etc. If you are looking for a free open source central authentication server that supports OAuth2, you should look at the Gluu Server http://gluu.org