Hello
i try to create an application that use REST Endpoint authenticate with Azure AD.
I create a Radzen Aplication and configure the Rest Data Service to use Azure Ad Auth and fetch data from a .net Core web api project.
I Open the solution in VS2019 and i see in startup.cs this configuration
services.AddAuthentication()
.AddCookie("TestRestSignInScheme")
.AddOpenIdConnect("TestRest", options =>
{
options.ResponseType = OpenIdConnectResponseType.CodeIdToken;
options.TokenValidationParameters.ValidateIssuer = false;
options.Authority = Configuration["TestRest:Authority"];
options.ClientId = Configuration["TestRest:ClientId"];
options.ClientSecret = Configuration["TestRest:ClientSecret"];
options.CallbackPath = new PathString("/test-rest-callback");
options.SaveTokens = true;
options.SignInScheme = "TestRestSignInScheme";
});
in the web api project i set this configuration
services.AddAuthentication(AzureADDefaults.BearerAuthenticationScheme)
.AddAzureADBearer(options => Configuration.Bind("AzureAd", options));
But when i call the endpoint i have the 401 unauthorized response....
Is the web api configuration correct?
Hi @Knuckles,
Unfortunately we can't tell if the configuration is correct or not. Does it work with other applications?
Hello
yes in other (custom) application with this configuration in blazorApp startup worked
services.AddAuthentication(AzureADDefaults.AuthenticationScheme)
.AddAzureAD(options => Configuration.Bind("AzureAd", options));
services.Configure<OpenIdConnectOptions>(AzureADDefaults.OpenIdScheme, options =>
{
options.ResponseType = "code";
options.SaveTokens = true;
//options.Scope.Add("offline_access");
//options.Scope.Add("User.Read");
options.Resource = "{clientID}";
options.ClientSecret = "{clientSecret}";
});
I see that when the code try to retrive the token
var accessToken = await contextAccessor.HttpContext.GetTokenAsync("TestRest", "access_token");
i have this result
PAQABAAAAAAAm-06blBE1TpVMil8KPQ41ARLOejoQg7gqL67ohJwID-Y1vEGTeU4EEFCui08aki3NbiPOHe-GMHDt3iXTpE0DGovL2RbBA-0kWdD4xxGs4wJ2-s3lPf-yo2M8K5VUXKcsCignlGj7x74vKQrDo_u3zbbJUG5zoc5K2cw4d2rkizHVBLuNZKKqM-654IWDpPWthWLPbGrCPCqQXJnOF0wCfBkFDEb7VSd0nVReNFoGVAYIGE5KgqFQ3WqMpRCqLC4-C-3ZO1I4R7CIDwfBNmB03cOvy4C_-WqaDhVdi5PGDMagQ3WDEdVVzKN-TM4Uwaw4hOidV9xnWrK-NTxcsDTG00NOhotn5i-GDveavdHVAbJrIvJyAwkwxbN88jz5DB-2DDJQW5gRT5ufZl9Th6tZXq2IGpF6eTGIvXDQYBng1D9Sg55Jl_Wt4IT1mRiLH2vlJ-A3cDCaBBJj3-bvu6Bke_GX9MBkdFdH-0lDKhmiHV7pZQD_c3CMtO1KXHktEs5a208mFW-rjSva-DG9laNVx8srdfq-74kjCplUQzbYC13S9-d7L9FB2_3jop95zCADPlwDqz2MuN60DhCJviFn_7USBoQmIcC4pNZalJNckOys3_BLZLNeco6I5gu9PN8gAA
and i think that is not a JWT token right?
You can try using the same configuration then. Here is how to extend the Startup.cs file.
hello
i try to extend the configuration but i have an error when i try to start the application.
OptionsValidationException: The 'Instance' option must be provided.
in the Startup.Custom.cs i have :
partial void OnConfigureServices(IServiceCollection services)
{
services.AddDevExpressBlazor();
services.AddAuthentication(AzureADDefaults.AuthenticationScheme)
.AddAzureAD(options => Configuration.Bind("AzureAd", options));
services.Configure<OpenIdConnectOptions>(AzureADDefaults.OpenIdScheme, options =>
{
options.ResponseType = "code";
options.SaveTokens = true;
//options.Scope.Add("offline_access");
//options.Scope.Add("User.Read");
options.Resource = "{clienId}";
options.ClientSecret = "{clientSecret}";
});
services.AddTransient<WeatherForecastService>();
}
and this is the appsetting.json
"TestRest": {
"ClientId": "{clientID}",
"ClientSecret": "{clientSecret}",
"Authority": "https://login.microsoftonline.com/{tenantID}
",
"Instance": "https://login.microsoftonline.com/
",
"Domain": "{domain}",
"TenantId": "{tenantID}"
},
"AzureAd": {
"Instance": "https://login.microsoftonline.com/
",
"Domain": "{domain}",
"TenantId": "{tenantID}",
"ClientId": "{clientID}"
}
but the "Instance" is provided in configuration....as I wrote earlier the "token" retrive is not a JWT token right? what is expected to extract when use the contextAccessor.HttpContext.GetTokenAsync("TestRest", "access_token"); ?
what is expected to extract when use the contextAccessor.HttpContext.GetTokenAsync("TestRest", "access_token"); ?
The access_token which is returned upon successful authorization.
ok i have this token returned..but is not a jwt token
Yes, the access_token is not a JWT token.
ok thanks...so what is it? if i know what is it i try to configure my webapi solution...
The access_token is returned by Azure AD itself - it should be JWT as per their documentation. I can't tell why your API returns an access_token which is not JWT.
By the way you said that your custom application works. How do you get the access_token there?
i have this code in _Host.cshtml
@{
var tokens = new InitialApplicationState
{
AccessToken = await HttpContext.GetTokenAsync("access_token"),
RefreshToken = await HttpContext.GetTokenAsync("refresh_token")
};
}
and this configuration
services.AddAuthentication(AzureADDefaults.AuthenticationScheme)
.AddAzureAD(options => Configuration.Bind("AzureAd", options));
services.Configure<OpenIdConnectOptions>(AzureADDefaults.OpenIdScheme, options =>
{
options.ResponseType = "code";
options.SaveTokens = true;
//options.Scope.Add("offline_access");
//options.Scope.Add("User.Read");
options.Resource = "{clientId}";
options.ClientSecret = "{clientSecret}";
});
whit this configuration
"AzureAd": {
"Instance": "https://login.microsoftonline.com/
",
"Domain": "{domain}",
"TenantId": "{tenantId}",
"ClientId": "{clientId}"
}
The code that Radzen generates uses an overload of exact same method:
HttpContext.GetTokenAsync("TestRest", "access_token");
Unfortunately I am out of any further suggestions.
I think yours is an auth code due to your reponseType = "code" I believe this must get posted to /token endpoint to get and access_token with the code grant flow.
OpenIdConnectResponseType.CodeIdToken
is "code id_token" and is similar to your code.
You can try customizing the generated code in Startup.cs via the code generation ignore list.
And maybe try AcquireTokenByAuthorizationCode
method
Yes you are right.
it returned the authorization_code and now with AcquireTokenByAuthorizationCode
i can obtain the id_token.
but when i try to get from HttpContext.GetTokenAsync("TestRest", "access_token");
i have null value
You could try the client_credentials flow with AcquireTokenForClientAsync()
instead of code grant like so:
HTH,
Josh