AWS: Cognito integration with a beta HTTP API in API Gateway? - amazon-web-services

Amazon Web Services introduced a beta release of HTTP API as a new product on API Gateway early last month. Its authentication is managed using JSON Web Tokens and configured with a form asking for
"Name of the Authorizer"
"Identity Source... a selection expression that defines the source of the token"
"Issuer URL"
I'm not very familiar with authentication protocols at all or what these form fields are asking, and currently the documentation from AWS on how to configure this to work with Cognito is sparse. I'm not totally comfortable configuring this without guidance due to my lack of experience. Another Stack Overflow user seemed to have a similar issue but didn't get an answer.

AWS is using JWT Bearer Grant for this purpose.
Draft Specification here.
It allows HTTP API Gateway to accept JWT Tokens in the incoming Authorization HTTP header containing a self-contained JWT access token issued by third-party authorization servers (like Cognito, Azure AD, etc).
API Gateway validates the incoming JWT Token by matching the 'iss' value with the issuer URL to see if it can trust this token.
Try with these values.
Name of the authorizer: Registered client name in your Cognito User Pool .
Identity Source: Leave it as default, $request.header.Authorization .
Issuer URL: Check the metadata URL of your Cognito User Pool (construct the URL in this format :: https://cognito-idp.[region].amazonaws.com/[userPoolId]/.well-known/openid-configuration :: look for a claim named "issuer". Copy its Value and paste it here.
Audience: Client ID of your Registered client in Cognito
Good Luck!
cheers,
ram

Used #ram answer to get through, and was able to implement this
1.Name of the authorizer:
AWS Cognito > User pools > App Integration > App client settings > App client :
Example : xxxxxx_app_clientWeb
2.Identity Source : $request.header.Authorization
3.Issuer URL
construct the URL to get Cognito user pool metadata ( https://cognito-idp..amazonaws.com//.well-known/openid-configuration)
Example :
https://cognito-idp.us-east-1.amazonaws.com/us-east-1_FcgSrx2141/.well-known/openid-configuration
open the URL and you will see a json
take the "issuer" value
Example :
"issuer":"https://cognito-idp.us-east-1.amazonaws.com/us-east-1_FcgSrx2141"
Take: https://cognito-idp.us-east-1.amazonaws.com/us-east-1_FcgSrx2141
4. Audience: AWS Cognito > User pools > App Integration > App client settings > App clientID
Example :
ID 9sptej55gii5dfp08ulplc343
Take: 9sptej55gii5dfp08ulplc343

This video explains the whole process and configuration like no other.
https://www.coursera.org/lecture/building-modern-java-applications-on-aws/use-amazon-cognito-to-sign-in-and-call-api-gateway-s226R
I am thankful that the video is public.
Note: (As far as I know) The course is from AWS but offered to the public through different MOOC websites (not just this one).
Once you have read & played enough, you will start seeing the gems within the details.
Token for example, is mentioned in many docs, but it can be Access / Id / Refresh Token. If you don't realize about this you can be wasting your time.
For example the "Implicit grant" doesn't provide a Refresh-Token, so you cannot renew your Access-Token and trying to do it is useless.

Related

Aws Cognito Bearer Token : Unable to obtain configuration from: 'System.String'

I am working on aws cognito with bearer token.
Below is the code to setup Bearer configuration.
I have written code to login via user name & password
I am able to logged in successfully and get the token
But when i am trying to access my authorise API it is throwing below error.
Could you please help me to resolve this?
Looks like your system is failing when trying to download OpenID Connect metadata. This will be a URL such as the following - so you should make sure your API is configured with a URL you can reach in the browser:
https://cognito-idp.eu-west-2.amazonaws.com/eu-west-2_qqJgVeuTn/.well-known/openid-configuration
The following type of code should work when validating Cognito tokens in .NET, if you add the Microsoft.AspNetCore.Authentication.JwtBearer library. Note that Cognito does not issue an Audience claim so you need to avoid validating it:
services
.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.Authority = "https://cognito-idp.eu-west-2.amazonaws.com/eu-west-2_qqJgVeuTn";
options.TokenValidationParameters = new Microsoft.IdentityModel.Tokens.TokenValidationParameters {
ValidateIssuer = true,
ValidateAudience = false,
};
});
Note that this includes a website library in APIs and expected OpenID Connect endpoints to exist. Personally I prefer not to write OAuth secured APIs like this.
JWKS ENDPOINT
The standard way to do API token validation is for the API to only know about the JWKS endpoint, as in these examples:
Node.js API JWT Validation
Java API JWT Validation
I found this approach a little harder in .NET, where libraries didn't quite do what I wanted. Here is some code that shows how to use extensibility points, in case useful:
.NET API JWT Validation

Alexa Skill with Azure AD B2C Auth expires after an hour

I am currently building an Alexa skill backed by Azure Functions (.NET Core/C#) and Azure AD B2C for authentication.
For the initial setup, I used mostly used the instructions found in this arcticle. Since, the article was written a couple of years ago, I had to make a few changes. In the end, I landed on the following configuration:
Azure Active Directory B2C
As I mentioned, we are using AAD B2C for authentication. Users of a related application are able to sign-up and sign-in to a React application. The idea is to provide an alternative interface for said users through Alexa intents + utterances.
I created an application for Alexa in AAD B2C with the following settings:
Properties
Web App / Web API: Yes
Allow implicit flow: Yes
Reply URLs: I entered the values provided by the Alexa skill setup (e.g. https://pitangui.amazon.com/api/skil/link/...); there are three different ones. I also added one for my azure function app (this is something that could be incorrect. It was part of what I did while diagnosing other earlier problems); it's in the format: https://myfuncname.azurewebsites.net/.auth/login/aad/callback (Do I even need this???)
App ID URI: https://myorg.onmicrosoft.com/alexa
Include native client: No
Keys
I generated a single App Key, which I'm using as the Secret in the Account Linking section in the Alexa Developer Console.
Many of the examples online mention setting an explicit expiration date here of 1 or 2 years; however, I am not presented with any options at all (i.e. no expiration option), just the code. Could this be part of the problem???
API Access
In the Published scopes section, the Scope's name is user_impersonation. The description is "Access this app on behalf of the signed-in user". The full scope value is: https://myorgsname.onmicrosoft.com/alexa/user_impersonation.
For API Access, I have to API entries here:
One that uses the user_impersonation scope mentioned above.
The second, titled "Access the user's profile", uses:
Acquire an id_token for users (openid)
Acquire a refresh_token for users (offline_access)
AAD B2C User Flow
The user flow that I'm using allows signing up and signing in, it utilizes the following configuration:
Properties
Misc
Enable JavaScript enforcing page layout (preview): On
Token lifetime
Access & ID token lifetimes (minutes): 60
Refresh token lifetime (days): 14
Refresh token sliding window lifetime: "Bounded".
Lifetime length (days): 90
Token compatibility settings
Issuer (iss) claim: https://<domain>/<b2c-tenant-guid>
Subject (sub) claim: ObjectID
Claim representing user flow: tfp
Session behavior
Web app session lifetime (minutes): 1440
Web app session timeout: Rolling
Single sign-on configuration: Tenant
Require ID Token in logout requests: No
Azure Function Authentication Middleware
For the authentication layer within the Azure Function, I'm utilizing the method described in the article mentioned above.
Alexa Developer Console
On the Alexa side of things, I have a really simple skill setup with the following settings:
Endpoint
My endpoint uses the HTTPS option with the default region set to the fully-qualified HTTPS endpoint of my Azure Function App's handler function.
The certificate set to "My development endpoint is a sub-domain of a domain that has a wildcard ..."
Account Linking
The account linking settings are as outlined below:
Do you allow uses to create an account or link to ...: Toggled On
Allow users to enable skill without account linking: Toggled On
Allow users to link their account to your skill from within your application or website: Toggled Off
Auth Code Grant: On
Authorization URI: https://myorg.b2clogin.com/myorg.onmicrosoft.com/oauth2/v2.0/authorize?p=<sign-in-user-flow-policy-name>
Access Token URI: https://myorg.b2clogin.com/myorg.onmicrosoft.com/oauth2/v2.0/token?p=<sign-in-user-flow-policy-name>
Your Client ID: AAD B2C App GUID
Your Secret: Key generated in App settings in AAD B2C for my Alexa Skill App (mentioned in the AAD B2C setup info above).
Your Authentication Scheme: HTTP Basic
Scope: openid and https://myorg.onmicrosoft.com/alexa/user_impersonation
Domain List: login.microsoftonline.com and myorg.b2clogin.com Note: This is probably wrong as I didn't know what to put here. The article above doesn't mention this setting at all
Default Access Token Expiration Time: 3600
Note: The Alexa Redirect URLS at the bottom are what I put in AAD B2C for the Reply URL section.
The Problem
Now for the most important part, The Problem. Everything seems to work at first...I'm able to go to alexa.amazon.com and utilize Link Account (which redirects me to and from my AAD B2C-driven login screen). Once I link accounts, I'm able to successfully utilize an utterance and receive a reply.
The problems starts when I wait an hour (I believe it's an hour). Attempting to initiate the Intent after an hour yields an error on the Azure Function app side of things when it tries to validate the Auth Token.
Can anyone provide me some guidance as to what I may have setup incorrectly or at least some things that I should look into? As I mentioned at the start of this question, many of the references that I'm finding online are out-of-date and do not cover all of the settings that I'm expected to utilize. Many of them are still using microsoftonline.com authority vs. b2clogin.com.
At a glance, I would assume that the problem is that the Alexa skill is failing to refresh its token after it expires after an hour. What do I need to do to ensure that it refreshes correctly?
I think that I have enough information at this point to go ahead and answer my own question. What I found was that the offline_access scope is necessary for Token Refresh to be possible.
Per Microsoft, "The offline_access scope gives your app access to resources on behalf of the user for an extended time. On the consent page, this scope appears as the "Maintain access to data you have given it access to" permission. When a user approves the offline_access scope, your app can receive refresh tokens from the Microsoft identity platform token endpoint. Refresh tokens are long-lived. Your app can get new access tokens as older ones expire.".
You can read more about it here.
To resolve the issue, I ensured that this scope was available in AAD B2C and added it as a referenced scope in the Alexa developer console.
Thanks for giving insight on offline_access. It took few hours to figure out how to implement offline_access. Interestingly offline_access works only with Azure AD, OAuth 1.0 endpoint and not with 2.0.
While trying with 2.0 it kept failing while account linking when multiple scopes were mentioned in Alexa configurations. The scopes I tried were as follows.
https://samplealexabackendapi/
https://graph.microsoft.com/offline_access
Finally I ended up working with OAuth 1.0 endpoint and using the scope https://samplealexabackendapi/.default which considers all scopes available to the app registered.

"Access token does not contain openid scope" in AWS Cognito

I am running a working AWS Cognito service on a frontend application which can successfully do the basic stuff - login, logout, signup, etc..
Right now I am trying to get user attributes through the backend API, such that:
1) The user login in the application and gets a JWT.
2) The JWT is being sent to the backend server.
3) The server has to extract the email of the user by using the access token
The closest thing that I found to what I need is this Cognito service.
So I am making a GET request to "https://mydomain.auth.eu-central-1.amazoncognito.com/oauth2/userInfo"
With Authorization Header as they are asking for, but I keep getting this response:
{
"error": "invalid_token",
"error_description": "Access token does not contain openid scope"
}
I have tried searching for this error but couldn't find any explanation about the error.
Thanks by advance
Erez, are you using a custom UI?
Because the custom UI uses flows that are completely separated from the OAuth2 ones (USER_SRP_AUTH, USER_PASSWORD_AUTH). Tokens that are released with these flows are not OpenID Connect compliant (basically they don't contain the openid scope) so you cannot use them to gather user infos (since the userinfo endpoint is OpenID Connect compliant and needs to be invoked with jwts compliant with OIDC standard).
We're also struggling on that, i'm sorry.
I had this exact problem and it was my fault. I was sending the id_token instead of access_token property of the token.
I program in PHP, so I was sending as header "Authorization: Bearer ".$token->id_token instead of "Authorization: Bearer ".$token->access_token. Now it works.
Hope it helps you or someone.
I am still experiencing the same issue. My problem relies on programmatic use of signIn service (not Hosted UI via federated login) in Amplify framework. After a long googling, I have discovered that this is because "openid" is not including in the scope of token. Only "aws.cognito.signin.user.admin" is included.
You can find a reference here, thread is still open https://github.com/aws-amplify/amplify-js/issues/3732
This solution seems to be fine for me How to verify JWT from AWS Cognito in the API backend?
If I understand correctly, you are successfully getting the #id_token sent to your front end from Cognito (steps 1-3). You can enable scopes on the #id_token by selecting the following options in your Cognito Pool App Client Settings:
I had a similar issue and I spent a couple of hours to find a solution. The access token you received it from cognito in your frontend application you need to send it to your backend then decode it and verify it. here is a good documentation from aws: https://docs.aws.amazon.com/cognito/latest/developerguide/amazon-cognito-user-pools-using-tokens-with-identity-providers.html

How do I integrate amazon cognito login in postman?

I was using Amazon Cognito user pool for login. When I access my web application, I get a redirect to
https://<domain>.auth.<region>.amazoncognito.com/login?response_type=code&client_id=<client id>&redirect_uri=<callback> .
Once logged in with the username/password of a user from the pool, I will be redirected to the callback URL with the code as a query parameter. I can use this to get tokens. How do I integrate this in postman so that I can use the token for my upcoming request?
I have an example of doing this...
The callback URL as defined in the Cognito User Pool console under App Integration / App client settings.
The URL for the login endpoint of your domain. This will be under Cognito User Pool / App Integration / Domain Name
Client ID is found under Cognito User Pool / General Settings / App clients
List the scopes you want to include in the Access Token. These must be enabled under Cognito User Pool / App Integration / App client settings. These can be either standard or custom scopes. Custom scopes are defined under App Integration / Resource servers and must include the resource server ID (e.g. https://myresource.com/myscope)
Click Request Token
You may now log in to your Cognito User Pool and receive an Access Token!
The problem is that once you have the Access Token it isn't usable within Postman because Cognito expects it to be bare and Postman automatically prepends 'Bearer' to the token:
The token can be used in cURL though:
curl -i -H "Authorization: dyJraWQiOiI1YVcwTUlqN1hBaHg4Yzh4Q3JNT2RsQjhZWjlCR3NQOE9BbkFlVFJtUklRPSIsImFsZyI6IlJTMjU2In0.eyJzdWIiOiI3YmEwZmMzOC01ZDcwkYS05MTI5ZTBmYTUzNTEiLCJ0b2tlbl91c2UiOiJhY2Nlc3MiLCJzY29wZSI6Imh0dHBzOlwvXC9hcGkubXk5MC5jb21cL3BvbGljZURlcGFydG1lbnRzLnJlYWQiLCJhdXRoX3RpbWUiOjE1NDA1OTIzMTYsImlzcyI6Imh0dHBzOlwvXC9jb2duaXRvLWlkcC51cy1lYXN0LTEuYW1hem9uYXdzLmNvbVwvdXMtZWFzdC0xX2xIbGo4NXpRYSIsImV4cCI6MTU0MDU5NTkxNiwiaWF0IjoxNTQwNTkyMzE2LCJ2ZXJzaW9uIjoyLCJqdGkiOiJhN2JiOWU2MC1kNmY1LTQ3ODYtODMwYi0xODdkZDZmYTZlODAiLCJjbGllbnRfaWQiOiI2MzhlYmZ1dTdiZDRkMXVkYnRzY2pxcnJncyIsInVzZXJuYW1lIjoicm9qbyJ9.O_GAxfFX3IQfLUu5Hxr05Wrk_2QDwNSL8tvDdEU0Dzs9d1XhQPafT6ney6yiGnKPOwsO8HhWdbT1QdDmByjuwQAURf1Da4Au7c-yhfgJcqWuHWZ4mledTSP8ukXqihMb4PoaDdU4JXyOdMLa50dBXVMgJNyXTpIulWOxFhiTW6DeQbnxNDk94cGNz_CTKCEqKStiloFZfLR7ndSrWqdOQ_SU__YV0RyKXZyK5yguv3nkUcI6cuKpbPVIZ5DNdpufbrtOLuZcC6HePBKrbTKjSZCt5-swy3YrwnY4ApTX7QUFzof6FylWaLA_KVP3Zv6ksSJ_IjBMFH1NRVHh4lbsOA" \
https://xxxxx.execute-api.us-east-1.amazonaws.com/v1/myresource/1234
by yl.
Thanks to Robert Jordan for his above postman OAuth2.0 configuration post.
I'll try to cover here the entire Cognito user pool definition part to make it easier.
Ok,
Open the Cognito console and follow the bellow stages:
1) create new user pool
name: Test1
left panel menu->Attributes
Select the following radio buttons:
o Email address or phone number - Users can use an email address or phone number as
their "username" to sign up and sign in.
o Allow email addresses
And checkboxes:
[v] email
[v] name
Screenshot:
Press the [Create Pool] button.
(if not available yet to the wizard - press [Review Details] option on the left panel menu)
2) left panel menu->App Clients
press: [add app client]
App client name: me1
clear all checkboxes but the:
[v] Enable username password based authentication (ALLOW_USER_PASSWORD_AUTH)
Leave Radio buttons as is:
o Enabled (Recommended)
Screenshot:
press [create app client]
3) copy and keep the 'App client id'
this is a string format similar to 5psjts111111117jclis0mu28q
Screenshot:
4) left panel menu->App Client settings
Enabled Identity Providers: [v]Select all
[v] Cognito User Pool
Callback URL(s): put the api gw url or https://www.google.com/
OAuth 2.0
Allowed OAuth Flows
[v] Implicit grant
Allowed OAuth Scopes
[v] openid
Screenshot:
5) left panel menu->Domain name
put a string in the prefix field, for instance: music123456789
check if available using the 'check' button.
your domain now is: https://music123456789.auth.us-east-1.amazoncognito.com
Screenshot:
6) left panel menu->Users and Groups
press [Create user]
Username (Required): Your.Mail#company.com
clear all [v] check boxes
Temporary password: Xx123456!
eMail: Your.Mail#company.com
7) in POSTMAN
Press new Request
enter the 'Authorization' tab
Select TYPE: OAuth 2.0
press the [Get new Access Token] button and fill in:
Token Name: myToken123
Grant Type: select 'implicit' from the listbox
callback URL: https://www.google.com/
(as in clause 4 or in cognito console->App Integration->App client settings)
Auth URL: https://music123456789.auth.us-east-1.amazoncognito.com/login
(as in clause 5 + '/login' suffix, what you have defined in cognito
console->App Integration->Domain Name)
Client ID: 5psjts343gm7gm7jclis0mu28q (the app client id - as in 3,
what you have defined in cognito console->General Settings->App clients)
Scope: openid (as in 4, what you have defined in cognito console->App
client settings->Allowed OAuth Scopes)
COGNITO to OKTA idp configuration
When connecting Cognito to Okta IDP, Configuration should be as follows:
Okta Setup
Cognito Setup
Postman setup
As an addition to very through explanations of Robert Jordan and ylev, I made it work by using the id_token instead of the Access Token.
In the token details page, copy the id_token and add it to the header manually without Bearer prefix:
Source: https://github.com/postmanlabs/postman-app-support/issues/6987
For those wanting to move away from the deprecated "implicit" grant to the recommended "authorization" aka "authorization code" grant, you'll want to have the following in Postman:
Grant Type: Authorization Code (Authorization Code with PKCE would prevent the code from being used by anyone else if it were intercepted in transit but either or... you probably want to start with getting "Authorization Code" working.)
Callback URL: https://oauth.pstmn.io/v1/callback (or whatever Postman sets it to when you check "Authorize using browser"
Auth URL: https://{app name you chose when creating the custom auth domain}.auth.{aws region}.amazoncognito.com/login e.g. https://myapp.auth.us-east-1.amazoncognito.com/login. You can find this in AWS Console -> Cognito -> the user pool -> App Integration tab -> Domain section -> Cognito domain (use the Actions dropdown to create a custom domain if you don't already have one).
Access Token URL: https://{app name}.auth.{aws region}.amazoncognito.com/oauth2/token e.g. https://myapp.auth.us-east-1.amazoncognito.com/oauth2/token.
Client ID: The Client ID corresponding to the "App Client" (e.g. the web app users will be authenticating through Cognito to use), found in AWS Console -> Cognito -> the user pool -> App Integration tab -> App Client List section -> the App Client.
Client Secret: An optional added security measure. This should never be sent to the web app as the client secret could then be extracted by a nefarious user via Chrome Dev Tools or the like. You can (and should) however use Client Secret with backend applications e.g. the API service backing your frontend web app. This is a decision that has to be made in AWS when the App Client is created within the Cognito User Pool, but don't fret- App Clients are easy to create/delete/recreate if you change your mind or pick the wrong setting.
Scope: OAuth uses "scopes" as a means of defining what the application which holds and uses the access token (e.g. some web app) can do/access on behalf of the user whose account it's using. It's similar to authorization in a web app (e.g. only users in the "admin" group can access the settings page) but it's meant to be authorization with respect to a user's metadata, so typically that manifests as user metadata the app has access to, for example the user's calendar or contacts or phone number. OAuth scope is not meant to replace an app's authorization system (e.g. RBAC) so if you're just making some web app and just need Cognito to handle user signup, storing and resetting passwords for users, etc. you can more or less ignore OAuth "scope", though you should probably be setting the "Scope" value in Postman to something like "openid email" (Scopes are separated by a single space and you can't request and obtain the "email" scope without also requesting "openid") so you at least get the user's email address in the access token to compare with your "Users" table in your app's database. Scope makes more sense and becomes more relevant in a scenario where your web app is authenticating with an actual third-party (not your own Cognito user pool), like Facebook or Google. Maybe you're making an app that syncs users' friends' contact data from Facebook to.. I don't know, a CSV file downloaded to your computer for backup purposes. In this case you want to request from Facebook's OAuth server the "friends-list" scope or whatever Facebook decided to call that scope. On the other hand, if you just need Facebook as a means for allowing your users to easily sign in to your app without having to create an account, you don't need the "friends-list" or any other scope from Facbeook (maybe just the scope that gives you the user's email address?).
Other fields:
Client Authentication: Send client credentials in body
Type: OAuth 2.0
Add authorization data to: Request Headers
Sources:
https://www.czetsuyatech.com/2021/01/aws-generate-cognito-access-token.html
https://aws.amazon.com/blogs/mobile/understanding-amazon-cognito-user-pool-oauth-2-0-grants/
https://api.slack.com/legacy/oauth-scopes
If your client supports USER_PASSWORD_AUTH you can request valid bearer tokens using the aws client.
read -s -p "Password: " && \
aws cognito-idp initiate-auth \
--client-id <client id> \
--auth-flow USER_PASSWORD_AUTH \
--auth-parameters "USERNAME=<username>,PASSWORD=$REPLY"
This can be added to Postman under Authorization / Type: Bearer Token.
For Postman 8.5.1 and AWS Chalice + Cognito user pool on the backend I have working example:
Cognito > User pools > > App integration > App client settings
About vars:
{{cognito_callback_url}} - Your Callback URL(s) from App client
settings
{{cognito_auth_url}} - Cognito > User pools >
> App integration > Domain name + /login
(https://.....auth.ap-south-1.amazoncognito.com/login)
{{cognito_client_id}} - Your App client web id from App client
settings
{{cognito_scope}} - Use 'openid'
Now click the Get the new access token in the bottom and authorize yourself using existing user data from pool
I thought i would post some more information about using cognito with an elastic load balancer. AWS load balancers do not current support auth via headers :( you can get it working on postman by copying cookies from a successfull web request into the postman request
The use-case you want to implement can be achieved by using the OAuth 2.0 authorization. If you can get the Auth URL/ Access Token URL, Client ID, and the Client Secret- you should be able to do it.
Here's a link to the documentation of the various authorization types we support including the above mentioned one- https://www.getpostman.com/docs/v6/postman/sending_api_requests/authorization.
Cheers.

How to get the accesstoken from alexa after account linking with azure AD

I tried to connect my Alexa AWS Lambda function (node.js 6.10) with Azure Activ Directory to my Azure-Cloud-API. After reading the documentation from amazon and many tutorials I have now a working Account Linking. That means, I can link the Account of the Skill inside the Alexa-App on my smartphone.
AccountLinking for my Custom Skill:
{Data from my azure portal}
Authorization Grant Type: Auth Code Grant
Authorization URI: {OAUTH 2.0 AUTHORIZATION ENDPOINT}
Access Token URI: {OAUTH 2.0 TOKEN ENDPOINT}
Client ID: b9c6[...]bc60 {Application ID}
Client Secret: {Client Secret}
Client Authentication Scheme: Credentials in request body
scope: openid
domain: empty
redirect urls: --> In Azure portal as ALLOWED TOKEN AUDIENCES and Reply URLs defined
In my aws lambda function I get the event request from alexa like the documentation says with properties for version, session, context, request...
My understanding of the documentation is, that the token I need for the Azure-Cloud-API-Request should be here: session.user.accessToken
But this token doesn't look like the one I need and after my test runs I get always "Unauthorized" back.
The Token looks something like this and is 1252 characters long:
AQABAAAAAADX8GCi6Js6SK82TsD2Pb7rqGN56iHT_YSxlSr1RAdXucGs0S3ykOaw0XZ1WnjJotqZAn9BH7agRbP0VQv2rnJuRw_aJil7 [...] JIEO2Ap4wuG-tTwiSmZBfbLhyYtwQmxLAkqiLApqFmBYcyu-dnzlVV4liDGyTQ7gAXufd3zt7QGmi3UfP1aL9f5NBeXbmxnU6FHRzF10QZa19pTQgNTtIK8oIAA
If I configure postman and send a request to the azure activ directory I get a accessToken like this (1168 characters long):
eyJ0eXAiOiJKV1QiLCJhbGc [...] Ezbk5aY2VEYyJ9.eyJhdWQiOiJodHRwczovL21ldGVvcmEtYXBwLmF [...] kY5MWVUUXdBQSIsInZlciI6IjEuMCJ9.KJco47-FdJ_eeqv38LL [...] YK_4JqCRDw
This one looks like a jwt-token and if I copy this token directly in my aws lambda function and use this one for the Azure-Cloud-API-Request it works (until the token expires).
Now I'm not sure if there is a problem in my configuration of the account linking? Or do I have to do something with the token from alexa to get the real one? Or is the real token somewhere else and I have to fetch it there?
Thanks a lot for your help!
Amazon Documentation "Alexa Skills Kit":
https://developer.amazon.com/docs/custom-skills/link-an-alexa-user-with-a-user-in-your-system.html
EDIT (Solution) 11.06.2018
Authorization Grant Type: Auth Code Grant
Authorization URI: {OAUTH 2.0 AUTHORIZATION ENDPOINT} + ?resource= + {Application ID}
Access Token URI: {OAUTH 2.0 TOKEN ENDPOINT}
Client ID: b9c6[...]bc60 {Application ID}
Client Secret: {Client Secret} App>Settings>Keys new Key with expiration date = 2 years
Client Authentication Scheme: Credentials in request body
scope: empty
domain: empty
redirect urls: --> In Azure portal as ALLOWED TOKEN AUDIENCES and Reply URLs defined
It sounds like you haven't completed the account linking sequence for your skill. After setting the account linking configuration you need to open the Alexa app (on your phone or https://alexa.amazon.com) and go to your new skill and link your account. Once that is successful you will get a token in request.Session.User.AccessToken.
The blog post: https://blogs.msdn.microsoft.com/premier_developer/2017/12/09/amazon-alexa-skills-authenticated-by-azure-active-directory-and-backed-by-asp-net-core-2-0-web-api-hosted-on-azure/ needs to be updated with the following:
You can ignore the sections about the "front end" app registration.
In Alexa account linking section update URLs to use login.microsoftonline.com instead of login.windows.net
ClientId to be the Application Id of the "back end" app registration
The ?resource= has to be set and has to be the same as the audience parameter for the JWT bearer options. This is ClientId if you use the .Net Core 2.0 template in Visual Studio.
The client secret (key) that is used can not be one that "Never Expires". Use a 1 or 2 year duration.
In addition to Nate's answer and following the addition of ?resource= to the Authorisation URI, I had to give the API permission Azure Active Directory Graph > User.Read on the App Registration and Grant Admin Consent to it.
Without this permission, the account linking would throw an error. If you have similar issues, try your OAuth values with Postman and check the Postman Console for error messages