You might have wondered how to add the Microsoft sign-in to certain corporate websites inside your company (which are available from the internet) in order to restrict access to employees of your organization only.

Microsoft sign in

At least I have, and it turned out to be not so difficult actually.

Why

Why would you want that? Because the alternative is to implement your own authentication and to store logins/passwords of your users somewhere. And if your company has more than 50 employees, that becomes more and more troublesome. So since your organization uses Office 365, it's just easier to rely on ready-made authentication provided by Microsoft.

I think, there are more ways to implement that, but I only found one. To give you some background, I am not an administrator of our Office 365 instance, I am just a regular developer. But what I do have (like other developers in our organization), is the Azure subscription, which, among other things, offers Azure Active Directory - and that's the thing that will allow you to add Microsoft sign-in to your website.

The following steps are based on the official manual.

Preparations

Azure App

Register a new App and set the following values.

Redirect URI:

https://YOUR-WEBSITE/signin-oidc

Who can use this application or access this API?

Accounts in this organizational directory only (YOUR ORGANIZATION only - Single tenant)

Logout URL:

https://YOUR-WEBSITE/signout-callback-oidc

Tokens you would like to be issued by the authorization endpoint:

ID tokens

Also check Branding section, in particular check the domain:

Azure App Branding

In my case I needed to change it to our organization's main domain.

Certificate

One of the requirements of Microsoft sign-in is https:// URL to your website, which means you need to:

  1. Have a domain;
  2. Have a certificate for that domain.

So I hope you already have a domain, because you won't be able to proceed without it. And Let's Encrypt will help with the certificate.

I would also recommend to use NGINX as a proxy server for your .NET Core website.

Be aware though that you are likely to get the following error:

AADSTS50011: The reply url specified in the request does not match the reply urls configured for the application
Reply URL error

If you take a look at the URL of the page where you get this error, you'll see that redirect_uri has http:// instead of https://:

https://login.microsoftonline.com/SOME/oauth2/v2.0/authorize?client_id=YOUR-CLIENT-ID&redirect_uri=http%3A%2F%2FYOUR-WEBSITE%2Fsignin-oidc

Make sure that your Kestrel runs with https:// (Program.cs):

public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
    WebHost.CreateDefaultBuilder(args)
        .UseUrls("https://localhost:5000")
        .UseStartup<Startup>();

And NGINX redirects requests to https://:

location / {
    proxy_pass https://localhost:5000;
    # ...
}

Implementation

I chose .NET Core MVC (although there are other examples as well), and here's an example project for that.

The most important part is these lines in Startup.cs:

public void ConfigureServices(IServiceCollection services)
{
    // ...

    services.AddAuthentication(AzureADDefaults.AuthenticationScheme)
        .AddAzureAD(options => Configuration.Bind("AzureAd", options));

    services.Configure<OpenIdConnectOptions>(AzureADDefaults.OpenIdScheme, options =>
    {
        options.Authority = options.Authority + "/v2.0/";
        options.TokenValidationParameters.ValidateIssuer = false;
    });

    services.AddMvc(options =>
    {
        var policy = new AuthorizationPolicyBuilder()
            .RequireAuthenticatedUser()
            .Build();
        options.Filters.Add(new AuthorizeFilter(policy));
    })
    .SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
}

And the following settings in appsettings.json:

{
  "...",
  "AzureAd": {
    "Instance": "https://login.microsoftonline.com/",
    "Domain": "YOUR-DOMAIN",
    "TenantId": "YOUR-TENANT-ID",
    "ClientId": "YOUR-CLIENT-ID",
    "CallbackPath": "/signin-oidc"
  }
}

TenantId and ClientId can be found in your App overview:

Azure App Overview

The last bit is to set [Authorize] attribute to your controllers:

[Authorize]
public class HomeController : Controller
{
    public IActionResult Index()
    {
        return View();
    }
}

This is it.

Deploy your website and check that Microsoft sign-in works and accepts only accounts from your organization:

Microsoft login with external account