Unable to get bearer token from Azure AD to use with API App
I have gone ahead and followed the tutorial to which you referred: Call an Azure API app from a web app client authenticated by Azure Active Directory
- Create an Azure API Api that returns contact data
- Deploy the API App to Azure App Service.
- Secure the API App using Azure Active Directory.
Then I was able to retrieve the token, and as you can see from the following demo, my code is no different than your code, except that it using a later version of the using Microsoft.IdentityModel.Clients.ActiveDirectory
libraries that use Async
.
Get access token from AAD
class Program
{
static void Main(string[] args)
{
var authContext = new AuthenticationContext(Constants.AUTHORITY);
var credential =
new ClientCredential(Constants.CLIENT_ID, Constants.CLIENT_SECRET);
var result = (AuthenticationResult)authContext
.AcquireTokenAsync(Constants.API_ID_URL, credential)
.Result;
var token = result.AccessToken;
Console.WriteLine(token.ToString());
Console.ReadLine();
}
}
Constants
AUTHORITY
. The first segment of this is https://login.microsoftonline.com. The final segment is an allowed tenant. We set the allowed tenant at portal.azure.com, going to the Gateway for our application, and choosing Settings > Identity > Azure Active Directory > Allowed Tenants. My tenant is bigfontoutlook.onmicrosoft.com.
CLIENT_ID
. We retrieve this client id from the application that we added to Azure Active Directory. Find this at manage.windowsazure.com > Active Directory > Your Directory > APPLICATIONS > Your Application > CONFIGURE. Once we have retrieved it, we must add it to our Gateway's Azure Active Directory settings in the Client ID field.
CLIENT_SECRET
. We create/retrieve this in the same location that we retrieve our client id.
API_ID_URL
. We retrieve this within the Gateway blade for our Web API App by choosing Settings > Identity > Azure Active Directory > App URL.
Here are the ones that work for me.
class Constants
{
public const string AUTHORITY =
"https://login.microsoftonline.com/bigfontoutlook.onmicrosoft.com/";
public const string CLIENT_ID =
"0d7dce06-c3e3-441f-89a7-f828e210ff6d";
public const string CLIENT_SECRET =
"AtRMr+Rijrgod4b9Q34i/UILldyJ2VO6n2jswkcVNDs=";
public const string API_ID_URL =
"https://mvp201514929cfaaf694.azurewebsites.net/login/aad";
}
Final decoded JWT
This is what the decoded JWT access token contains.
{
typ: "JWT",
alg: "RS256",
x5t: "MnC_VZcATfM5pOYiJHMba9goEKY",
kid: "MnC_VZcATfM5pOYiJHMba9goEKY"
}.
{
aud: "https://mvp201514929cfc350148cfa5c9b24a7daaf694.azurewebsites.net/login/aad",
iss: "https://sts.windows.net/0252f597-5d7e-4722-bafa-0b26f37dc14f/",
iat: 1442346927,
nbf: 1442346927,
exp: 1442350827,
ver: "1.0",
tid: "0252f597-5d7e-4722-bafa-0b26f37dc14f",
oid: "5a6f33eb-b622-4996-8a6a-600dce355389",
sub: "5a6f33eb-b622-4996-8a6a-600dce355389",
idp: "https://sts.windows.net/0252f597-5d7e-4722-bafa-0b26f37dc14f/",
appid: "0d7dce06-c3e3-441f-89a7-f828e210ff6d",
appidacr: "1"
}.
Note: It's a throwaway app in a throwaway active directory account with a throwaway resource group, so showing my security credentials is a non-issue.
Diagram just to be sure :)
trailmax
tech.trailmax.info - My blog. I write about C# and ASP.Net MVC (and sometimes about other random stuff) hrnet.trailmax.info My other blog. There I write about a technology I have been exposed for longer than I wanted. And now I know too much about HR.Net. This is part of my consulting service.
Updated on June 19, 2022Comments
-
trailmax almost 2 years
I have an MVC application that needs to access private API App in Azure that is protected with Azure AD authentication. So I need to get Azure AD bearer token, transfer it into
Zumo-Auth
token and use it to access the API App.I'm going through this tutorial and everything is working fine until the point when I need to request the token from
authContext
. Here is the snippet of a code:var authContext = new AuthenticationContext( "https://login.microsoftonline.com/MyADDomain.onmicrosoft.com"); ClientCredential credential = new ClientCredential( "04472E33-2638-FAKE-GUID-F826AF4928DB", "OMYAPIKEY1x3BLAHEMMEHEHEHEHEeYSOMETHINGRc="); // Get the AAD token. var appIdUri = "https://MyAppGateway-814485545465FAKE4d5a4532cd.azurewebsites.net/login/aad"; //var appIdUri = "https://MyADDomain.onmicrosoft.com/MyAppName"; //var appIdUri = "https://MyADDomain.onmicrosoft.com/"; //var appIdUri = "https://graph.windows.net"; AuthenticationResult result = authContext.AcquireToken(appIdUri, credential); // <-- can't get the token from AD // downhill from here var aadToken = new JObject(); aadToken["access_token"] = result.AccessToken; var appServiceClient = new AppServiceClient( "https://MyAppGateway-814485545465FAKE4d5a4532cd.azurewebsites.net/"); // Send the AAD token to the gateway and get a Zumo token var appServiceUser = await appServiceClient.LoginAsync("aad", aadToken);
The line with
authContext.AcquireToken(appIdUri, credential)
is the one causing trouble.If as
appIdUri
I givehttps://MyAppGateway-814485545465FAKE4d5a4532cd.azurewebsites.net/login/aad
, I get exception:400: AdalServiceException: AADSTS50001: Resource 'https://MyAppGateway-814485545465FAKE4d5a4532cd.azurewebsites.net/login/aad' is not registered for the account.
But this exact line is in the list of
Reply Url
in the AD ApplicationWhen I try to use
https://MyADDomain.onmicrosoft.com/MyAppName
orhttps://MyADDomain.onmicrosoft.com/
asappIdUri
I get a different exception message:400: AdalServiceException: AADSTS50105: Application '04472E33-2638-FAKE-GUID-F826AF4928DB' is not assigned to a role for the application 'https://MyADDomain.onmicrosoft.com/MyAppName'
Or
400: AdalServiceException: AADSTS50105: Application '04472E33-2638-FAKE-GUID-F826AF4928DB' is not assigned to a role for the application 'https://MyADDomain.onmicrosoft.com/'
In both cases I had the
App ID URI
in the AD Application set to 'https://MyADDomain.onmicrosoft.com/MyAppName' or 'https://MyADDomain.onmicrosoft.com/'. And both of the names in the list ofReply URL
.Eventually after enough tries I have put
https://graph.windows.net
asappIdUri
and got the bearer token back. But the token was given with expiry date in the past (about 1 minute in the past). So I could not do anything further with this. And got401-Unauthenticated
when tried to use the token to login into API App.What am I missing?
-
trailmax over 8 yearsThanks for this, I'll give it a go tomorrow.
-
trailmax over 8 yearsYou know wha? I copied your code, put my guids, secrets and urls. And got the same damned exception again! Then I created a whole new Api app and a new AD Application. Copied the credentials and everything worked. Not sure what exactly was broken, but I suspect AD App was messed up beyond recognition.
-
Shaun Luttin over 8 yearsYup. Sometimes troubleshooting makes a mess :)
-
Jaxidian over 7 yearsI just want to add that I ran into this exact same problem with the exact same errors and the exact same solution (start over and try again). The thing is, I've now started over and tried again about 8 times and only 5 of the 8 times has it worked. Something seems to be unreliable with this - I don't know if this is due to the Preview'ness of the tooling or what, but it doesn't seem to be terribly reliable. :-/
-
Shaun Luttin over 7 years@Jaxidian I was facing something like that once with OAuth, and it turned out to be the difference between using HTTP and HTTPS. Have you checked that?
-
Jaxidian over 7 years@ShaunLuttin Thanks. Fortunately (unfortunately?) I figured out the unpredictable behavior. It's predictable once you account for delayed engagement of the "User assignment required?" setting. With that enabled (and waiting a minute), it 100% fails with the OP's error. No matter what, I cannot seem to figure out how to "assign" the client application to the web api application.