Skip to content

Authentication

OAuth: Client Credentials

  • Used by clients to obtain an access token outside of the context of the user
  • No user login prompt
  • The client credentials are passed directly
curl --location --request GET 'https://login.microsoftonline.com/tenant-id/oauth2/token' \
  --header 'Content-Type: application/x-www-form-urlencoded' \
  --form 'grant_type="client_credentials"' \
  --form 'client_id="client-id"' \
  --form 'client_secret="client-secret"' \
  --form 'resource="https://storage.azure.com"' # The protected resource (a access token is valid only for this resource)
  • In order to access a resource, you must pass the access token under the Authorization header and the api version under x-ms-version (E.g., 2017-11-09)
# resource="https://storage.azure.com"
curl --location --request GET 'https://hvitoi.blob.core.windows.net/{container-name}/sample.txt' \
--header 'Authorization: Bearer bearer-token' \
--header 'x-ms-version: 2017-11-09'
# resource="https://vault.azure.net"
curl --location --request GET 'https://hvitoi.vault.azure.net/secrets/{secret-name}/{secret-version}?api-version=7.1' \
--header 'Authorization: Bearer bearer-token' \
--header 'x-ms-version: 2017-11-09'
# resource="https://graph.microsoft.com"
curl --location --request GET 'https://graph.microsoft.com/v1.0/users' \
--header 'Authorization: Bearer bearer-token' # Retrieve data about all AD users

Microsoft Authentication Library

  • Library:
  • Allow developers to acquire tokens from the Microsoft Identity Platform
  • You don't need to directly work with OAuth libraries in yor code
  • Fetch tokens on behalf of the user or application
  • Maintains a token cache and refreshes when they are about to expire
  • The redirect URI must be specified at the Application Object under Manage/Authentication tab
  • Add a platform configuration: web, single-page, android, desktop, etc
  • E.g., https://localhost:44366/signin-oidc (login)
  • E.g., https://localhost:44366/signout-oidc (logout)
<ItemGroup>
  <!-- Basic connectivity with MS Identity Platform -->
  <PackageReference Include="Microsoft.Identity.Web" Version="1.9.2" />

  <!-- Graphic screen prompt for login -->
  <PackageReference Include="Microsoft.Identity.Web.UI" Version="1.9.2" />

  <!-- Policy builder authorization -->
  <PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="3.1.13" />

  <!-- User interface for signin/signout -->
  <PackageReference Include="Microsoft.AspNetCore.Identity.UI" Version="3.1.13" />
</ItemGroup>
// appsettings.json
{
  "AllowedHosts": "*",
  "AzureAd": {
    "Instance": "https://login.microsoftonline.com/", // authorization server
    "TenantId": "tenant-id",
    "ClientId": "client-id",
    "CallbackPath": "/signin-oidc", // route that receives the code (redirect uri  )
    "SignedOutCallbackPath": "/signout-oidc"
  },
  "ConnectionStrings": {
    "OAuth_2ContextConnection": "Data Source=OAuth-2.db"
  }
}
public class Startup
{
  public Startup(IConfiguration configuration) { Configuration configuration; }
  public IConfiguration Configuration { get; }

  // Add services to the container
  public void ConfigureServices(IServiceCollection services)
  {
    services.AddControllersWithViews();

    // Set up scope of access that the consent screen will ask to the user (not necessary for ID tokens)
    string[] scopes = new string[] { "https://storage.azure.com/user_impersonation" }; // user_impersonation: use all roles assigned to the logged in user

    // "AzureAd" stores the configuration to connect to the authorization server
    services
      .AddMicrosoftIdentityWebAppAuthentication(Configuration, "AzureAd")
      .EnableTokenAcquisitionToCallDownstreamApi(scopes)
      .AddInMemoryTokenCaches();

    services.AddRazorPages().AddMvcOptions(options =>
    {
      var policy = new AuthorizationPolicyBuilder().RequireAuthenticatedUser().Build();
      options.Filters.Add(new AuthorizeFilter(policy));
    }).AddMicrosoftIdentityUI(); // user interface for signin/out
  }

  // Configure the HTTP request pipeline
  public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
  {
    if (env.IsDevelopment())
    {
      app.UseDeveloperExceptionPage();
    }
    else
    {
      app.UseExceptionHandler("/Home/Error");
      // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
      app.UseHsts();
    }
    app.UseHttpsRedirection();
    app.UseStaticFiles();

    app.UseRouting();

    app.UseAuthentication(); // protects the page
    app.UseAuthorization();

    app.UseEndpoints(endpoints =>
    {
      endpoints.MapControllerRoute(
        name: "default",
        pattern: "{controller=Home}/{action=Index}/{id?}");
    });
  }
}

Open ID Connect

public void ConfigureServices(IServiceCollection services)
{
  services.AddControllersWithViews();
  services.AddAuthentication(options =>
  {
    options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
    options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
  })
    .AddCookie(CookieAuthenticationDefaults.AuthenticationScheme)
    .AddOpenIdConnect(OpenIdConnectDefaults.AuthenticationScheme, options =>
      {
        options.SignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
        options.Authority = "https://login.microsoftonline.com/{tenant-id}";
        options.ClientId = "{client-id}";
        options.ResponseType = OpenIdConnectResponseType.Code;
        options.ResponseType = OpenIdConnectResponseType.IdToken;
        options.SaveTokens = true;
        options.Scope.Add("profile");
        options.Scope.Add("openid");
        options.ClientSecret = "{client-secret}";
      });
}