asp.net-coremicrosoft-graph-apimicrosoft-graph-sdksmicrosoft-graph-calendarhosted-blazor-webassembly

Should I use Client credential flows for enabling Microsoft Graph API for my webapp that has a module to get list of conference rooms?


We're working on a web app that will be used by a specific client. One of their requests is that the app should only work for their organization. We've set up authentication using asp.net identity. Now, for a particular feature, we need to fetch a list of conference rooms within their organization and know if these rooms are available.

I'm considering using the Client Credential Flow to enable the Microsoft Graph API, which would allow us to retrieve the list of rooms and their availability. Does this seem like the right way to go?

I know that it requires configuration & admin consent for initial setup.

Let me know your thoughts and if you need more details.

Note: We simply need a module that can retrieve conference room details for the company and indicate room availability (However, this should only work for that specific organization; individuals from personal or different organizations should not be able to access it.)


Solution

  • For enabling Ms Graph API into your application, you have to implement the authentication, for client credential flow, you need Azure AD app + correct API permission + admin consent. But for some other common flow such as auth code flow, you also need to integrate Ms indentity in your application so that users could sign in with their microsoft account and get authorized to call Ms Graph API, while client credential flow doesn't demand the user-sign-in operation.

    In your scenario, you already have asp.net core identity, it looks like you don't have specific requirement to add another authentication scheme. Therefore, the client credential flow looks the best option for you.

    Let's see the authorization for client credential flow, what you need is client id, client secret, and the scope is always http://graph.microsoft.com/.default.

    POST /{tenant}/oauth2/v2.0/token HTTP/1.1           //Line breaks for clarity
    Host: login.microsoftonline.com:443
    Content-Type: application/x-www-form-urlencoded
    
    client_id=535fb089-9ff3-47b6-9bfb-4f1264799865
    &scope=https%3A%2F%2Fgraph.microsoft.com%2F.default
    &client_secret=sampleCredentia1s
    &grant_type=client_credentials
    

    And for auth code flow, you have to sign in first to get the auth code, then you could use auth code to generate the access token and use it to call graph API.

    get auth code:

    https://login.microsoftonline.com/{tenant}/oauth2/v2.0/authorize?
    client_id=6731de76-14a6-49ae-97bc-6eba6914391e
    &response_type=code
    &redirect_uri=http%3A%2F%2Flocalhost%2Fmyapp%2F
    &response_mode=query
    &scope=https%3A%2F%2Fgraph.microsoft.com%2Fmail.read
    &state=12345
    &code_challenge=YTFjNjI1OWYzMzA3MTI4ZDY2Njg5M2RkNmVjNDE5YmEyZGRhOGYyM2IzNjdmZWFhMTQ1ODg3NDcxY2Nl
    &code_challenge_method=S256
    

    get access token with auth code:

    POST /{tenant}/oauth2/v2.0/token HTTP/1.1
    Host: https://login.microsoftonline.com
    Content-Type: application/x-www-form-urlencoded
    
    client_id=6731de76-14a6-49ae-97bc-6eba6914391e
    &scope=https%3A%2F%2Fgraph.microsoft.com%2Fmail.read
    &code=OAAABAAAAiL9Kn2Z27UubvWFPbm0gLWQJVzCTE9UkP3pSx1aXxUjq3n8b2JRLk4OxVXr...
    &redirect_uri=http%3A%2F%2Flocalhost%2Fmyapp%2F
    &grant_type=authorization_code
    &code_verifier=ThisIsntRandomButItNeedsToBe43CharactersLong 
    &client_secret=JqQX2PNo9bpM0uEihUPzyrh    // NOTE: Only required for web apps. This secret needs to be URL-Encoded.
    

    By the way, I noticed you have a blazor-web-assembly tag in your question, if this is the project where you want to add graph API code in, you are not allowed to use client credential flow, because this is a client app while client credential flow is only support in a daemon application like web api or blazor server app. You have to integrating microsoft identity and use the auth code flow. For blazor web assembly integrating Azure AD and calling Graph API, you might refer to this sample.

    ==============================================

    builder.Services.AddHttpClient();
    
    //CookieAuthenticationDefaults.AuthenticationScheme
    builder.Services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
    .AddCookie(x => x.LoginPath = "/account/login");
    builder.Services.AddAuthentication()
        .AddMicrosoftIdentityWebApp(builder.Configuration.GetSection("AzureAd"), OpenIdConnectDefaults.AuthenticationScheme, "ADCookies");
    
    // Add microsoft identity ui would make you have a LoginPartial view and we could modify this view to add asp.net core identity sign in
    builder.Services.AddControllersWithViews().AddMicrosoftIdentityUI();
    

    and then in the view, we might integrating both of the authentication scheme with 2 groups of buttons.

    @using System.Security.Principal
    
    <ul class="navbar-nav">
        @if (User.Identity.IsAuthenticated)
        {
            <li class="nav-item">
                <span class="navbar-text text-dark">Hello @User.Identity.Name!</span>
            </li>
            <li class="nav-item">
                <a class="nav-link text-dark" asp-controller="Account" asp-action="LogOut">log out</a>
            </li>
            @*asp - area = "MicrosoftIdentity"*@
        }
        else
        {
            <li class="nav-item">
                <a class="nav-link text-dark" asp-controller="Account" asp-action="Login">log in</a>
            </li>
        }
    </ul>
    
    @*<ul class="navbar-nav">
        @if (User.Identity.IsAuthenticated)
        {
            <li class="nav-item">
                <span class="navbar-text text-dark">Hello @User.Identity.Name!</span>
            </li>
            <li class="nav-item">
                <a class="nav-link text-dark" asp-area="MicrosoftIdentity" asp-controller="Account" asp-action="SignOut">Sign out</a>
            </li>
        }
        else
        {
            <li>user is : @User.Identity.Name  + @User.Identity.IsAuthenticated</li>
            <li class="nav-item">
                <a class="nav-link text-dark" asp-area="MicrosoftIdentity" asp-controller="Account" asp-action="SignIn">Sign in</a>
            </li>
        }
    </ul>*@
    

    Finally we need to keep the user in Azure AD and the user in our own database having mapping relationship, or in other words, I have an account with @xx.onmicrosoft.com and another account with @xxx.com, but the application should know both of the accounts are mine.