alexa skill account linking fails at token endpoint - oauth

alexa skill doesnot send "client secret" in the request to the token endpoint which fails the account linking in my OAuth server.
The request body contains :
{ 'grant_type': 'authorization_code',
'code': '*******',
'redirect_uri': 'https://pitangui.amazon.com/api/skill/***',
'client_id': '******' }

The client secret should not be sending from the Alexa URL but it used for identify the request as coming from Alexa
Secret ID => "A credential you provide that lets the Alexa service authenticate with the Access Token URI. This is combined with the Client ID to identify the request as coming from Alexa."

Related

Authenticate Azure API Management with OAuth2 using Azure AD

I am trying to secure APIM APIs using OAuth2 via AzureAD by reading the article: Protect a web API backend in Azure API Management by using OAuth 2.0 authorization with Azure AD
AzureAPIM - OAuth2
Authorization endpoint URL (v1): https://login.microsoftonline.com/{tenant}/oauth2/authorize
Token endpoint URL (v1): https://login.microsoftonline.com/{tenant}/oauth2/token
Client ID: client-app id
Redirect URI: (deprecated portal): https://xxx-api.portal.azure-api.net/docs/services/auth1/console/oauth2/authorizationcode/callback
AzureAD - backend-app:
scope: Files.All
AzureAD - client-app:
secret key: xxx
Redirect url: ONLY WORK with deprecated portal in APIM (https://xxx-api.portal.azure-api.net/docs/services/auth1/console/oauth2/authorizationcode/callback)
For Demo Conference API, Add Validate JWT policy to Inbound processing where 3a0cf09b- is tenant id and b7c31179- is backend-app application id:
In Developer portal, the authentication to AzureAD is successful with a return token:
However the authorization is failed with calling the API:
Inspecting the received token in jwt.io, I found that the "aud": "00000003-0000-0000-c000-000000000000" is not backend-app application id:
{
"aud": "00000003-0000-0000-c000-000000000000",
"iss": "https://sts.windows.net/3a0cf09b-xxx/",
"app_displayname": "client-app",
"appid": "05a245fb-xxx",
"scp": "Files.Read User.Read profile openid email",
"tenant_region_scope": "OC",
"tid": "3a0cf09b-2952-4673-9ace-0e1bf69ee23a",
"unique_name": "user1#xxx.onmicrosoft.com",
}
API Test HTTP response trace shows the error on validate-jwt:
validate-jwt (-0.138 ms)
{
"message": "JWT Validation Failed: Claim value mismatch: aud=b7c31179-xxx.."
}
Replacing aud by the value in the token 00000003-0000-0000-c000-000000000000 or removing the required-claims in the validate-jwt policy to get it working.
Any idea please?
From your error report, it is indeed a 401 error, that is, your aud does not match the api you want to call, I use the auth code flow to do a simple demonstration for you:
First expose the api of the back-end application and add the client application.
Next,under 'API permissions', give your front-end application access to your backend api:
Under 'API permissions' click on 'Add permission', then click on the 'My APIs' tab.
Find your backend application and select the appropriate scope.
Click 'Add permissions'.
Grant admin consent for your APIs.
Get token:
Parse the token:
It seems you choose v1 endpoint of OAuth2 authorization but not v2 endpoint, so the value of aud in access token should be like b7c31179-xxxx.... but not api://b7c31179-xxxx..... So there are no mistakes in your steps of get access token.
According to some test in my side, the cause of this problem is you did not specify a parameter resource with the value of the backend-app application id when you configure OAuth2.0 in your APIM. The document you refer to also mentions this (I test with not specify this parameter, it shows same problem with yours)
So to solve this problem, please go to your APIM and click "OAuth 2.0" tab, edit the item you created. Add a parameter resource with value of the backend-app application id.
Note: When you add the parameter resource and click "Save" button, please open the item again and check if the "Client secret" box is empty. When I test in my side, the "Client secret" box shows empty after add parameter resource, it may be a bug on that page. If "Client secret" is empty, it might show error message like The request body must contain the following parameter: 'client_assertion' or 'client_secret' when you get the access token in Developer portal.

What is the redirect_uri in Alexa Skill Activation API?

Background
I'm implementing Alexa's App-to-App Account Linking Flow, and I'm stuck on Step 6 - enabling the skill using Alexa's Skill Activation API.
Concretely, I am not sure what value to supply to the redirect_uri POST field. In the docs, the following description is provided:
The redirect_uri parameter that was included in the authorization request to your OAuth 2.0 server to obtain the user's authorization code. This enables Amazon to retrieve access tokens from your token server. This URL must be opaque to Amazon.
My understanding is that Alexa wants to exchange an existing authorization code for an access token, but I don't know how Alexa is trying to accomplish this "under the hood" and my current approach throws a 400 error.
Error Message
[status] 400
[response] {"message":"Could not contact provider of account linking credentials"}
Notes
My app uses Firebase authentication, and creates accounts for users via federated login with Google and Facebook. Thus, Google and Facebook redirect back to my native app (React Native).
I do not have a universal link; instead in my account-linking flow,
the Alexa app redirects users to an html page that redirects to my app using its custom schema.
When a user signs into my app from Alexa, Alexa redirects them from my login page back to the Alexa app. In this case, the Alexa universal link is the redirect url.
When a user signs into Alexa from my app (app-to-app linking), The Alexa app redirects them to my app. My app is the redirect url.
I have tried using my app's [faux] "universal link" as the redirect url, to no avail. There are no other redirects in my login flows. What is this url supposed to be?
NB: I have a endpoint for exchanging an auth_code for an access_token. The token is returned in the body; there's no redirect with the access_token appended to the redirect_url.
Example Skill Activation (my React Native app):
async enableSkill() {
try {
let response = await fetch(`https://api.amazonalexa.com/v1/users/~current/skills/${this.skillId}/enablement`, {
method: 'POST',
headers: {
'Authorization': `Bearer ${this.alexaAccessToken}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
stage: 'development', // or live
accountLinkRequest: {
redirectUri: Linking.makeUrl(), // <--- unsure
authCode: this.myAppAuthCode, // <-- auth code from my system, not Alexa's
type: "AUTH_CODE"
}
})
});
return response.json();
} catch (err) {
throw new Error(err);
}
}
I think it is not possible to use different OAuth Server like Google and Facebook together. I am not sure if it is possible to use firebase as OAuth Server.
In the account linking tab of the skill, you have to enter the details of the OAuth server you want to use and in the accountLinkRequest you must enter the redirectUri which you used for the OAuth Login with this server.
When you have your own OAuth server make sure it is running on port 443. It took me hours to find out that it is not working with Port 3000 which my Node.js backend used.
According to the developer documentation The redirect_uri you are asking about is a parameter that was included in the authorization request to your OAuth 2.0 server to obtain the user's authorization code. This enables Amazon to retrieve access tokens from your token server. You must set this URL in the developer console of your skill like that:

Invalid Access Token in FitBit

i'm trying to integrate the Fitbit SDK in my iOS app. I have created project on fitbit now i'm running there API in Postman to check profile, but in response it is showing me invalid access token,
{
"errors": [
{
"errorType": "invalid_token",
"message": "Access token invalid: 39ec7defa6f0e33b314bbf6217279b15. Visit https://dev.fitbit.com/docs/oauth2 for more information on the Fitbit Web API authorization process."
}
],
"success": false
}
This is my API https://api.fitbit.com/1/user/-/profile.json and this is what i'm passing in header, Authorization : Bearer Client Secret But it is showing me status code 401 having error of invalid access token . How can i get the access token for my app?
You need to get an OAuth2.0 token from the FitBit authentication service before you can call any other endpoints on the API. You will need to redirect your app to Safari and go to the fitbit authentication service so that the user can log in and authorise your apps access to their FitBit data. The callback will then return an OAuth token that you can pass in subsequent requests.
You will need to call something like this:
https://www.fitbit.com/oauth2/authorize?response_type=code&client_id=%#&scope=%#&redirect_uri=%#"
This is the official fitbit documentation for Authorisation:
https://dev.fitbit.com/build/reference/web-api/oauth2/

When exchanging the Amazon Alexa grant_code for an access_token, where are the credentials?

I am trying to write the exchange and access endpoints and the docs here (https://developer.amazon.com/public/solutions/alexa/alexa-skills-kit/docs/linking-an-alexa-user-with-a-user-in-your-system#h2_login) are not clear on a couple of things:
how is the call to exchange a grant code for access token made - is it GET with credentials in QS or is it a POST with credentials in a body?
Is the access token delivered only in the JSON for an intent call or is it set properly as a bearer token?
It's a POST with credentials in the request body. Amazon follows the Oauth2 RFC correctly in this case.
The access token is delivered by Amazon only in the JSON for the intent request and not properly set as a bearer. This is annoying.
In my case, I had to hack around it by first validating if the request was a valid alexa request which contained a session with an access token, then setting the HTTP_AUTHORIZATION header to Bearer <token>, then using existing request auth logic to authenticate (I was using Django with django-oauth-toolkit, so YMMV if you're using something else).
That code looks something like this:
# get the access_token from the POST request
if access_token is not None:
request.META["HTTP_AUTHORIZATION"] = "Bearer " + access_token
if not hasattr(request, 'user') or request.user.is_anonymous():
user = authenticate(request=request)
if user:
request.user = request._cached_user = user
if request.user.is_authenticated():
# Do whatever with the logged in user

Google+ Sign-in for server-side apps, exchanging auth code for access token

I'm trying to follow this flow to sign-in a user on an android app using a python server backend:
https://developers.google.com/+/web/signin/server-side-flow
I'm successful in getting the authorization code from the Android app, but when I try to exchange this code for an access token from the server, I'm getting an "invalid_request" error.
From the Android app, I'm using the same client_id as the one on the server which is listed under "Client ID for web application" in my console. I've verified the redirect_uri is correct. Is it not possible to generate an authorization code from an Android client and use a server to exchange for the access token?
My python code is:
def auth_params(self):
client_id, client_secret = self.get_key_and_secret()
return {
'grant_type': 'authorization_code',
'code': self.data.get('code', ''), # auth code from app
'client_id': client_id,
'client_secret': client_secret,
'redirect_uri': self.get_redirect_uri()
}
#classmethod
def auth_headers(cls):
return {'Content-Type': 'application/x-www-form-urlencoded',
'Accept': 'application/json'}
def auth_complete(self, *args, **kwargs):
params = self.auth_params()
request = Request('https://accounts.google.com/o/oauth2/token', data=urlencode(params),
headers=self.auth_headers())
try:
response = simplejson.loads(urlopen(request).read())
except HTTPError, e:
print 'fml'
There are two special redirect URIs that do not actually redirect back to the server: "postmessage" and "urn:ietf:wg:oauth:2.0:oob". These special redirect URIs do not trigger a redirect POST to your server but instead return the OAuth 2.0 tokens in a response to the request.
When you exchange the code for an access token and refresh token, the redirect URI associated with the authorization code needs to match.
Because your authorization code is coming from an Android device, your redirect URI is probably mismatched on this line:
'redirect_uri': self.get_redirect_uri()
For Android code exchange, the redirect URI must be:
urn:ietf:wg:oauth:2.0:oob
Hopefully that helps. As you may have noticed, if you are also taking an authorization code returned from a Web sign-in or Android, you will need to set the redirect URI appropriately (e.g. urn[...] for Android, 'postmessage' or the configured redirect otherwise).

Resources