adding call api to web app - mattchenderson/microsoft-identity-web GitHub Wiki
You have a web app that signs-in users and now you want to call a web API...
Your startup.cs has the following content:
public void ConfigureServices(IServiceCollection services)
{
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddMicrosoftIdentityWebApi(Configuration, "AzureAd");
///
}
The appsettings.json is like the following:
{
"AzureAd": {
"Instance": "https://login.microsoftonline.com/",
"Domain": "msidentitysamplestesting.onmicrosoft.com",
"TenantId": "7f58f645-c190-4ce5-9de4-e2b7acd2a6ab",
"ClientId": "86699d80-dd21-476a-bcd1-7c1a3d471f75",
"CallbackPath": "/signin-oidc",
"SignedOutCallbackPath ": "/signout-callback-oidc",
// To call an API
// "ClientSecret": "[Copy the client secret added to the app from the Azure portal]",
//"ClientCertificates": [
// {
// "SourceType": "",
// "Container": "",
// "ReferenceOrValue": ""
// }
//]
}
}
And you now want call a web API. Here is how to proceed.
Add the following methods after AddMicrosoftIdentityWebApi
:
.EnableTokenAcquisitionToCallDownstreamApi()
.AddInMemoryTokenCaches();
producing:
public void ConfigureServices(IServiceCollection services)
{
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddMicrosoftIdentityWebApi(Configuration, "AzureAd")
.EnableTokenAcquisitionToCallDownstreamApi()
.AddInMemoryTokenCaches();
}
In the AzureAd section add:
"ClientSecret": "xxx-ttt-zzzz"
In the AzureAd section add:
"TodoList": {
/*
TodoListScope is the scope of the Web API you want to call. This can be: "api://a4c2469b-cf84-4145-8f5f-cb7bacf814bc/access_as_user",
- a scope for a V2 application (for instance api://b3682cc7-8b30-4bd2-aaba-080c6bf0fd31/access_as_user)
- a scope corresponding to a V1 application (for instance <GUID>/user_impersonation, where <GUID> is the
clientId of a V1 application, created in the https://portal.azure.com portal.
*/
//"TodoListScope": "api://a4c2469b-cf84-4145-8f5f-cb7bacf814bc/.default",
"TodoListScope": "api://a4c2469b-cf84-4145-8f5f-cb7bacf814bc/access_as_user",
"TodoListBaseAddress": "https://localhost:44351"
},
For the moment your controller is like the following:
[Authorize]
[Route("api/[controller]")]
public class TodoListController : Controller
{
// The web API will only accept tokens 1) for users, and 2) having the access_as_user scope for this API
static readonly string[] scopeRequiredByApi = new string[] { "access_as_user" };
public TodoListController()
{
}
// GET: api/values
[HttpGet]
public async Task<IEnumerable<Todo>> Get()
{
HttpContext.VerifyUserHasAnyAcceptedScope(scopeRequiredByApi);
}
If you want to call graph (scopes "user.read"), you need to:
- Inject a
ITokenAcquisition
service in the constructor of the controller (or the page) - In the controller action, use the
ITokenAcquisition
to acquire a token for the specified scope. - Add
[AuthorizeForScopes(Scopes = new string[]{"user.read" })]
on the controller action, or the Razor page. This is to automatically handle conditional access and incremental consent. For details see Managing incremental consent and conditional access
[Authorize]
[Route("api/[controller]")]
[AuthorizeForScopes(Scopes = new string[]{"user.read" })]
public class TodoListController : Controller
{
// The web API will only accept tokens 1) for users, and 2) having the access_as_user scope for this API
static readonly string[] scopeRequiredByApi = new string[] { "access_as_user" };
private readonly ITokenAcquisition _tokenAcquisition;
public TodoListController(ITokenAcquisition tokenAcquisition)
{
_tokenAcquisition = tokenAcquisition;
}
// GET: api/values
[HttpGet]
public async Task<IEnumerable<Todo>> Get()
{
HttpContext.VerifyUserHasAnyAcceptedScope(scopeRequiredByApi);
var token2 = await _tokenAcquisition.GetAccessTokenForUserAsync(new string[] { "user.read" });
}
// GET: api/values
[HttpGet]
public async Task<IEnumerable<Todo>> Get()
{
HttpContext.VerifyUserHasAnyAcceptedScope(scopeRequiredByApi);
cancellationToken = GetTheCancellationToken(); // for instance from some context.
TokenAcquisitionOptions options = new TokenAcquisitionOptions {CancellationToken = cancellationToken}
var token2 = await _tokenAcquisition.GetAccessTokenForUserAsync(new string[] { "user.read" }, tokenAcquisitionOptions: options );
}