I am creating custom skill in Alexa which uses account linking. I have created my own authentication server using OAuth2 php library and I have configured the authorization url and token urls in skill configuration.
When I try account linking from Alexa mobile app, I get error 'unable to link your skill'. following is my work progress.
Alexa app is able to open my authentication url.
I am able authorize and provide authorization code with redirect uri.
Alexa is requesting for access token using authorization code previously provided.
I am able validate authorization code and response back with access token and refresh token.
Alexa fails in this step to link with my skill. It say's 'Unable to link your skill'.
I have gone through my forums about the same, but couldn't find what exactly the issue is. Could any one please help me out in this regard.
I was facing the same issue too , the problem was solved by selecting "credentials in request body" (default being Http basic) for "Client Authentication Scheme", since the access token in my case was sent in the body of the message. Check how the authentication token is sent by your server.
If your redirect link is currently:
https://layla.amazon.com/api/skill/link/xxxxxxxxxxxxxx?code=xxxxxxxxx&state=xxxxx
You need to change the ? to a #
e.g.
https://layla.amazon.com/api/skill/link/xxxxxxxxxxxxxx#code=xxxxxxxxx&state=xxxxx
Thought this might help anyone wondering how the Alexa service is posting to their OAuth endpoint since it's pretty opaque and undocumented. The redirect to the Alexa service initiates a POST request to the defined OAuth endpoint with the post body in x-www-form-urlencoded format not JSON. So the POST looks like this.
POST /authentication/1/oauth HTTP/1.1 url.Values{} grant_type=authorization_code&code=XXXXXXXXXXXXXXXXXXXXXXXXX&redirect_uri=https%253A%252F%252Fpitangui.amazon.com%252Fapi%252Fskill%252Flink%252FM9BEOG3DM65SQ&client_id=XXXXXXXXXXXXXXXXXXXXXX
If your endpoint isn't parsing this data or expecting some format that can be unmarshaled easily then it is probably failing with a 406 response.
In my case the problem was with the Client secret,
In google developer console add your skill redirect URIs
and recheck the client secret you provide in the alexa skill Authorization grant type
My issue was with the final AccessToken call. I was assuming it was using a GET request, so I only catered for this in my function. It is actually creating an access token. So it's using a POST.
After I updated my function to use a post and return the AccessToken in JSON format it all works fine.
Maybe the following steps will help you identify the problem:
Add console.log('LOGS', response) to your Lambda function.
Activate the skill and login in the Alexa app
Go back to your Lambda function and check the last logs for the LOGS entry.
If you find that the Lambda function is invoked than the problem is not from your OAuth server, but you may need to handle the "AcceptGrant directive" in your Lambda function as it is motioned here: https://developer.amazon.com/en-US/docs/alexa/device-apis/alexa-authorization.html#directives
adjust your Lambda function to:
exports.handler = function (request, context) {
if (request.directive.header.namespace === 'Alexa.Authorization' && request.directive.header.name === 'AcceptGrant') {
log("DEBUG:", "Authorization request", JSON.stringify(request));
handleAcceptGrant(request, context);
}
function handleAcceptGrant(request, context) {
var response = {
event: {
header: {
"namespace": "Alexa.Authorization",
"name": "AcceptGrant.Response",
"messageId": request.directive.header.messageId,
"payloadVersion": "3"
},
payload: {}
}
};
log("DEBUG", "Alexa.Authorization ", JSON.stringify(response));
context.succeed(response);
}
If the problem is with the AcceptGrant then The account linking should be now successful.
Related
I just wanted to know how can we validate the azure ad access token in a backend API in my case i.e. Django rest framework.
Consider that I have a single page app or a native app and a backend API (django rest framework) completely independen of each other. In my case if my single page app/native app wants to access certain data from the backend API, and inorder to access the API, user should be logged in the backend API.
So what my approch is to make use of MSAL library to get the access token from the SPA/native app and then once token is acquired, pass that token to backend API, validate it, get the user info from graph api. If user exists in the DB then login the user and pass the required info. If user info doesn't exist then create the user, login and pass the info from the API.
So my question is when I pass the access token to my backend api, how can I validate that the token that a user/SPA/native app has passed to backend API is valid token or not?
Is it just we need to make an API call to graph API endpoint with accessToken that user/SPA/native passed and if it is able to get the user data with the accessToken then then token is valid or if it fails then the accessToken is invalid.
Is it the general way to validate the token or some better approach is there? Please help
Good day sir, I wanna share some of my ideas here and I know it's not a solution but it's too long for a comment.
I created a SPA before which used msal.js to make users sign in and generate access token to call graph api, you must know here that when you generate the access token you need to set the scope of the target api, for example, you wanna call 'graph.microsoft.com/v1.0/me', you need a token with the scope 'User.Read, User.ReadWrite' and you also need to add delegated api permission to the azure app.
So as the custom api of your own backend program. I created a springboot api which will return 'hello world' if I call 'localhost:8080/hello', if I wanna my api protected by azure ad, I need to add a filter to validate all the request if has a valid access token. So I need to find a jwt library to decode the token in request head and check if it has a token, if the token has expired and whether the token has the correct scope. So here, which scope is the correct scope? It's decided by the api you exposed in azure ad. You can set the scope named like 'AA_Custom_Impression', and then you can add this delegate api permission to the client azure ad app, then you that app to generate an access token with the scope of 'AA_Custom_Impression'. After appending the Bearer token in calling request, it will be filtered by backend code.
I don't know about python, so I can just recommend you this sample, you may try it, it's provided by microsoft.
I've solved the similar issue. I don't found how to directly validate access token, but you can just call graph API on backend with token you've got on client side with MSAL.
Node.js example:
class Microsoft {
get baseUrl() {
return 'https://graph.microsoft.com/v1.0'
}
async getUserProfile(accessToken) {
const response = await got(`${this.baseUrl}/me`, {
headers: {
'x-li-format': 'json',
Authorization: `Bearer ${accessToken}`,
},
json: true,
})
return response.body
}
// `acessToken` - passed from client
async authorize(accessToken) {
try {
const userProfile = await this.getUserProfile(accessToken)
const email = userProfile.userPrincipalName
// Note: not every MS account has email, so additional validation may be required
const user = await db.users.findOne({ email })
if (user) {
// login logic
} else {
// create user logic
}
} catch (error) {
// If request to graph API fails we know that token wrong or not enough permissions. `error` object may be additionally parsed to get relevant error message. See https://learn.microsoft.com/en-us/graph/errors
throw new Error('401 (Unauthorized)')
}
}
}
Yes we can validate the Azure AD Bearer token.
You can fellow up below link,
https://github.com/odwyersoftware/azure-ad-verify-token
https://pypi.org/project/azure-ad-verify-token/
We can use this for both Django and flask.
You can directly install using pip
but I'm not sure in Django. If Django install working failed then try to copy paste the code from GitHub
Validation steps this library makes:
1. Accepts an Azure AD B2C JWT.
Bearer token
2. Extracts `kid` from unverified headers.
kid from **Bearer token**
3. Finds `kid` within Azure JWKS.
KID from list of kid from this link `https://login.microsoftonline.com/{tenantid}/discovery/v2.0/keys`
4. Obtains RSA key from JWK.
5. Calls `jwt.decode` with necessary parameters, which inturn validates:
- Signature
- Expiration
- Audience
- Issuer
- Key
- Algorithm
I'm using the Google Smart Home action and my skill is successfully linked. Getting a below SYNC intent.
{
"requestId": "ff36a3cc-ec34-11e6-b1a0-64510650abcf",
"inputs": [{
"intent": "action.devices.SYNC"
}]
}
But not getting the Authorization token to call the cloud api (As we getting in Alexa), So how can I get the Authorization token?
Google attach user's access token on Authorization header when call your fulfillment URL, as the following document Fulfillment and authentication:
When you have authenticated a user, the user's third-party OAuth 2 access token is sent in the Authorization header when smart home intents are sent to your fulfillment.
I was able to resolve it by checking the API Gateway logs, I was receiving the access token on api gateway but api gateway was sending only body part to the function not the header.
So what you need to do is just add the header manually in the request(for your function) and then you will surely receive that access token.
I am attempting to convert over from the old Azure AD OpenId Connect to use the new Azure AD v2.0 endpoint as documented here: https://learn.microsoft.com/en-us/azure/active-directory/develop/active-directory-v2-protocols-oidc
When I attempt to request a token via the v2.0 token endpoint: https://login.microsoftonline.com/common/oauth2/v2.0/token
I get a response that only includes a 'token_id' field, and not a 'token_type', or any other fields. The library I am using to parse the response is nimbus.com library for openid and auth2. The OIDCTokenReponseParser throws an exception because the 'token_type' is missing from the response.
I have looked at the OpenID Connect Protocol specifications, and it says that a request to the token endpoint requires 'token_type', so it seems as though the response from the endpoint is invalid.
Has anyone run into this issue, and if so, how did you deal with it?
UPDATE 3/2/2018
My flow works with the old end point. I redirect the user here:
https://login.microsoftonline.com/common/oauth2/authorize?response_type=code&client_id={id}&redirect_uri={uri}&scope=openid+profile+email&state={state}
The user logs in, and they are redirected to my app, and code is provided via a query parameter.
I turn around and make this request:
https://login.microsoftonline.com/common/oauth2/token?code={code}&grant_type=authorization_code&client_secret={secret}
And I get response that looks like this.
{
"token_type": "Bearer",
"expires_in": "3599",
"ext_expires_in": "0",
"expires_on": "1520018953",
"access_token": "{token}",
"refresh_token": "{token}",
"id_token": "{token}"
}
I try to handle v2.0 version the same way. I redirect the user to:
https://login.microsoftonline.com/common/oauth2/v2.0/authorize?response_type=code&client_id={id}&redirect_uri={uri}&scope=openid+profile+email&state={state}
And after they sign in, they are redirected back to my app with the 'code' as a query parameter.
I then send this request:
https://login.microsoftonline.com/common/oauth2/v2.0/token?code={code}&grant_type=authorization_code&client_secret={secret}&redirect_uri={uri}&client_id={id}
But this is the response I get:
{
"id_token":"{token}"
}
The scopes you've requested can all be satisfied with the contents of the ID Token only. In your Auth Request, try including a scope that would indicate that you need an access token (e.g. https://graph.microsoft.com/User.Read), and the response will have the expected token_type and access_token.
I've written a simple React app, following the instructions of a slightly out of date tutorial that is meant to display a list of contacts in the sidebar with individual contact data displayed in an index component but only if you have been authenticated by logging into an Auth0 component and have a JSON Web Token kept in local storage. I have confirmed that I am logged in and have the token. Everything up to this point is working fine.
The problem begins when I click on a contact in the sidebar to view that contact's data, which comes down from a pretty basic API set up with Express. I've been using Postman to troubleshoot since the only error I get from app is "401: Unauthorized"
When I hit my endpoint, suppling an Authorization header with "Bearer [JWT_VALUE_HERE]" Postman responds with "UnauthorizedError: invalid algorithm"
The full output
UnauthorizedError: invalid algorithm
at /Users/Arkham/Documents/Web/eldrac/react-auth-server/node_modules/express-jwt/lib/index.js:102:22
at /Users/Arkham/Documents/Web/eldrac/react-auth-server/node_modules/jsonwebtoken/verify.js:27:18
at _combinedTickCallback (internal/process/next_tick.js:95:7)
at process._tickCallback (internal/process/next_tick.js:161:9)
I've done a bit of googling and tweaked my Auth0 client settings, specifically the Algorithm settings but no matter what I set it to (my options are RS256 and HS256), it doesn't seem to make a difference. I'm dying to get past this.
I use Superagent to make my request
getContact: (url) => {
return new Promise((resolve, reject) => {
request
.get(url)
.set('Authorization', 'Bearer ' + AuthStore.getJwt())
.end((err, response) => {
if (err) reject(err);
resolve(JSON.parse(response.text));
})
});
}
Which seems to be working. I have confirmed that the url is correct and that AuthStore.getJwt() are supplying the correct parameters.
Your question does not provide much information necessary to diagnose the issue - First of all, you should be sending a JWT Access token to the API, not your Id Token.
Upfront questions:
Do you have an API defined in the Auth0 Dashboard?
When you authenticate, are you using an audience parameter? It is
likely that the Access Token is using RS256. Remember for an access
token and Resource API, it is the API that controls the algorithm,
not the Client.
What algorithm is your API using to verify the token?
Presumably, the url in your code snippet is something like
http://localhost:3001/myendpoint?
Take your token, and paste it at https://jwt.io to see what the algorithm used is. Compare that with what is being used to verify the token.
Shall update my answer here as you give more information - please use comments section for this answer.
Hi so I have been trying to make an app that uses a Biq Query API.
All the authentication and client secrets for OAuth2 work fine when I load the app locally, however after deploying the code I get the following error:
Error: redirect_uri_mismatch
Request Details
scope=https://www.googleapis.com/auth/bigquery
response_type=code
redirect_uri=https://terradata-test.appspot.com/oauth2callback
access_type=offline
state=https://terradata-test.appspot.com/
display=page
client_id=660103924069.apps.googleusercontent.com
But looking at my API Console, I find that the redirect uri https://terradata-test.appspot.com/oauth2callback is in my list or redirect uri's:
Redirect URIs:
1.https://terradata-test.appspot.com/oauth2callback
2.http://terradata-test.appspot.com/oauth2callback
3.http://1.terradata-test.appspot.com/oauth2callback
4.https://code.google.com/oauthplayground
I'm not sure what I'm missing to fix this problem? Why is there a redirect error with a uri that is listed in the API console?
The app builds the OAuth2 decorator to pass through to the Biq Query API like this:
CLIENT_SECRETS = os.path.join(os.path.dirname(__file__),
'client_secrets.json')
decorator = oauth2decorator_from_clientsecrets(
CLIENT_SECRETS,
'https://www.googleapis.com/auth/bigquery')
http = httplib2.Http(memcache)
bq = bqclient.BigQueryClient(http, decorator)
Is there any more code I should put to clarify the situation? Any input would be greatly appreciated. Thanks so much!
Shan
In standard web server OAuth 2.0 flows (authorization code), there are 3 places the redirect_uri is used. It must be identical in all three places:
In the URL you redirect the user to for them to approve access and
get an authorization code.
In the APIs console
In the
server-to-server HTTPS post when exchanging an authorization code
for an access token (+ maybe a refresh token)
You haver to create an API credentials with next steps on
https://console.cloud.google.com/apis/credentials
Client Oauth Id
Web Type
JavaScript authorized -> https://yourapp.appspot.com
URIs authorized -> https://yourapp.appspot.com/oauth2callback
This is the credentials you have to use in local app before deploy