Calling an Azure AD B2C-secured ASP.NET Core Web API 2 from JavaScript

Wow that’s a blog post title I never thought I’d write considering I started the year blogging all the things related to Git and GitHub! 🙂  I should come full circle and have Hubot call a B2C-secured API using coffeescript! Hmm…

In my previous post, you saw how to create a new ASP.NET Core Web API 2 and secure it using Azure AD B2C. Today’s blog post discusses how to call this API from a Single Page Application (think javascript).

Why not just make the call as before? Because you’ll get this error message:

Error calling the Web api:
error

If you open up the Developer Tools – Console window, you’ll see the full error message:

Failed to load https://localhost:44332/hello: Response to preflight request doesn’t pass access control check: No ‘Access-Control-Allow-Origin’ header is present on the requested resource. Origin http://localhost:6420 is therefore not allowed access. The response had HTTP status code 404.

Using CORS on an ASP.NET Core Web API 2

I’m following this how to article on enabling CORS in an ASP.NET Core application.

Using my example API (here’s the diff), you’ll first want to add CORS to your ConfigureServices() method in Startup.cs

public void ConfigureServices(IServiceCollection services) {
  services.AddCors();

Next, you’ll want to configure Cors in your Configure method

public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) {
  app.UseCors(builder =>
    builder.WithOrigins("http://localhost:6420").AllowAnyHeader().AllowAnyMethod());

And that’s it! Now run your application.

Note that…

I had to use AllowAnyHeader() and AllowAnyMethod(). I thought this might be implied since the article didn’t call it out. I’m also curious if there’s a way to tighten this even more. I practice paranoia-driven development.

Updating the Single Page App to call the B2C protected Resource

I’m using the Azure AD B2C MSAL.js sample. Why this sample? No particular reason. It was the just first B2C javascript sample I learned.

First, you’ll want to register this app in your B2C Tenant. Don’t forget to provide API-level access to this app.

Clone the repo, open in VSCode, and update the B2C coordinates in index.html in this section. For b2cScopes and webApi, I left the ones from the previous blog post.

clientID:'your application id for your SPA',
authority:"https://login.microsoftonline.com/tfp/.onmicrosoft.com/",
b2cScopes: ["https://.onmicrosoft.com/HelloCoreAPI/demo.read"],
webApi:'https://localhost:44332/hello',

That’s it! To start your SPA, go to the command line and in the same directory as server.js run node server

Now log into the web application and call the API. And you’ll see “Hello there!” returned!

Note: if you forget to provide API-level permissions to the SPA in the Azure B2C portal, you’ll see an error message that popups are being blocked. Open the Developer Tools – Console window and click the link for the full error message.

Securing an ASP.NET Core Web API 2 using Azure AD B2C

In a previous post you saw how to secure and call an ASP.NET Web API using Azure AD B2C. Today’s post is how to secure an ASP.NET Core Web API 2. This blog post walks you through the steps from File – New – Project to using Postman to test your API with an access token. Here’s the official ASP.NET Core sample

Create the project

Since this is my first ASP.NET Core project, I spent some time playing with the getting started first-web-api tutorials.

  • File – New – Project – .NET Core – ASP.NET Core Web Application
  • I called mine HelloCoreAPI, because in my previous post I had registered a HelloAPI and you need to use an unique App ID URI
  • Select Web API
    • Make sure ASP.NET Core 2.0 is selected (I’m using VS 2017 so it’s the default)
    • Make sure No Authentication is set

And hit F5 just to make sure things are working.

Create the /hello endpoint

I spent some time exploring the documentation on ASP.NET Core routing.

  • I deleted the default ValuesController since I won’t be using it
  • Right click on the Controllers folder, and add a new API Controller – Empty
  • Call it HelloController – just like picking up your mouse and saying “Hello Computer!”

I’ve setup my route to look like

 

[Route("hello")]
[HttpGet]
public IActionResult Hello() {
    return Ok("Hello There");
}
  • Open launchSettings.json and for both profiles (or just the IIS Express profile) change “launchUrl” to “hello” – the preceding ‘/’ is handled by the “ApplicationURL”

Hit F5 and see “Hello there!”

Enable https

I happened to see this on twitter today while writing this blog post. For cross-platform support, check out this blog post: https://blogs.msdn.microsoft.com/webdev/2017/11/29/configuring-https-in-asp-net-core-across-different-platforms/

  • Go to Project Properties – Debug and check Enable SSL
  • In `launchSettings.json` change both the `applicationURL` to the new https address

According to the enforcing SSL docs, you should also do

services.Configure<MvcOptions>(options =>
{
     options.Filters.Add(new RequireHttpsAttribute());
});

F5 to make sure everything’s good

Register the API application in B2C

  • Go to the Azure Portal and make sure you are in the right tenant!
  • In B2C, go to Applications and click New Application
  • Give the application a name you can identify, like Hello Core API
  • This is a Web API so click Web API
  • Under reply URL use the https address that opens when you hit F5, e.g. https://localhost:44332
  • Under API ID URI, give it a unique name. Since I have a previous example, I shall call this API, creatively, HelloCoreAPI
  • Hit create
  • Create the “demo.read” scope under Published Scopes

Enter the B2C coordinates

In appsettings.json add the following:

"AzureAdB2C": 
  {
    "Tenant": "<your tenant name>.onmicrosoft.com", 
    "ClientId": "<the application id you just registered>",
    "Policy": "<your sign up sign in policy e.g. B2C_1_SiUpIn>",
    "ScopeRead": "demo.read"  
  },

Setup Middleware

  1. in Startup.cs – ConfigureServices(), we’ll want to initialize the JWT Bearer middleware to validate tokens since this is an ASP.NET Core Web API.
public void ConfigureServices(IServiceCollection services) {
  services.AddAuthentication(options => {
    options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
    })
      .AddJwtBearer(jwtOptions => {
         jwtOptions.Authority = $"https://login.microsoftonline.com/tfp/{Configuration["AzureAdB2C:Tenant"]}/{Configuration["AzureAdB2C:Policy"]}/v2.0/";
         jwtOptions.Audience = Configuration["AzureAdB2C:ClientId"];
         jwtOptions.Events = new JwtBearerEvents
         {
            OnAuthenticationFailed = AuthenticationFailed
         };
    });

  services.AddMvc();
}

2. In Startup.cs, add the AuthenticationFailed method for locally debugging this sample only. Note how the repo readme instructs you not to use this handler in production scenarios.

3. In Startup.cs, create a public static field called ScopeRead

4. In Startup.cs Configure() add

ScopeRead = Configuration["AzureAdB2C:ScopeRead"];
app.UseAuthentication(); 
...
app.UseMVC();

Secure the API call itself

  1. Add the Authorize attribute to the class level in HelloController.cs
[Authorize]
public class HelloController : Controller

2. Make sure the user has the right scopes for the API.

public IActionResult Hello() {

  var scopes = HttpContext.User.FindFirst("http://schemas.microsoft.com/identity/claims/scope")?.Value;
  if (!string.IsNullOrEmpty(Startup.ScopeRead) && scopes != null && scopes.Split(' ').Any(s => s.Equals(Startup.ScopeRead))) {
     return Ok("Hello There");
  }
  else
  {
     return Unauthorized();
  }
 }

Whenever I’m debugging a B2C call to an API, I set a breakpoint inside the API to make sure I know which Unauthorized I’m debugging.

If you hit F5, you’ll get a 401 unauthorized error, because this user agent isn’t authorized, so any breakpoints you set within the method won’t get hit.

How to test your API

From a previous blog post, you can use the Policy Run Now feature and Postman to debug.

My code sample is at https://github.com/saraford/HelloCoreAPI

My API app registration in the B2C portal looks like

ASP.NET Core API app registration in B2C

Next blog post: How to call this ASP.NET Core Web API from a Single Page Application.

Testing a B2C secured Web API using Postman

In my post yesterday on Securing a Web API, I asked how might I test my API after securing it, since I didn’t have a client app created yet.

Of course, there is a way using Postman.

I’ve mentioned previously how to use the “run now” policy feature to test your policy and review your tokens. That previous blog post used a web application. Today’s blog posts uses a native app as the selected application.

Go to your B2C_1_SiUpIn policy:

  1. Under Select application, chose Hello API WPF App. 
  2. Under Select reply url, choose the https url
  3. Expand Access Tokens and under Select resource, select Hello API (or whateer name you gave your API from yesterday’s blog post). Make sure all the scopes are selected.

Here’s what my Run Policy Settings look like.

Sign Up or Sign In policy run now page
Click Run now. You’ll see a new browser tab appear. Copy the resulting URL and open up your favorite flavor of notepad.

access token in the reply url

Make sure you only copy the access token and none of the other parameters that come after the access_token. This had me scratching my head for a good half-hour.

Open up https://jwt.ms and paste in the access token to confirm it all looks good and contains the claims you’re Hello API is expecting, e.g. “read”

reviewing scopes in jwt.ms

Next, fire up Postman. Also, make sure your Hello API project is running 🙂

I’m still new to Postman, so YMMV. If you have a different way of using Postman for this scenario, please let me know!

  1. Choose GET and insert the URL for your Hello API /hello endpoint.
  2. Under Headers, type in Authorization
  3. For its value, type in Bearer then the access token.

Postman with a bearer tokenAnd if all is setup correctly, you’ll get the expected response!

I’m still working on a blog post on how to debug all these steps for creating a client application and an API for use with B2C. Stay tuned!

Securing and calling a web API using Azure AD B2C

This blog post walks you through creating and securing an ASP.NET Web API to work with B2C. You’ll call your new API from an existing B2C sample WPF application. I chose the WPF application example since this type of client app requires the fewest line changes to setup.

Note: The Azure Docs are securing a web API and calling a web API. This blog post is my “if I could go back in time, here’s what I would tell myself.”

When I first started learning Azure AD B2C, I thought it was adequate for 100 lv content that the samples to only contain a client application to obtain an id token. Perhaps this makes sense for the very first module in a B2C course. However, most apps want to do more than just authenticate and show your display name from the id_token. If you want to do more than just greet your users, your client app need to acquire an access token so it can put it to use, e.g. accessing some resource like an API.

btw: if you are only using an id token, I’d love to learn more about your scenarios!

Note you have to register your own APIs with B2C. You can’t use someone else’s API for demo purposes because the client ID and tenant name would be different. Trust me I went down this path several times before the “oh yeah – that’s right” moment finally hit home and stuck with me.

Demo code

The API in this sample returns a Hello <username> if the user is authorized.

The code sample that goes alongside this blog post is at https://github.com/saraford/HelloAPI-blog-post

Creating the Web API

  1. Open a new instance of Visual Studio. (In this example, I’m using Visual Studio 2017, but if there’s interest for 2015 steps, lmk!)
  2. Go to File – New – Project and choose Web – ASP.NET Web Application (.NET Framework)
  3. Choose Web API
  4. Name your project HelloAPI and click OK
  5. Leave authentication as No Authentication – otherwise, it installs Microsoft.Owin.Security.ActiveDirectory that uses the WindowsAzureActiveDirectoryBearerAuthentication middleware that doesn’t work with B2C tokens.

Create a route

Before we jump into authorizing our route, let’s make sure our API works properly.

  1. On the Controllers folder, right-click and select Add – Controller 
  2. Select Web API 2 Controller – Empty and then click Add
  3. Name the controller HelloController

Next, we’ll add a new route


[Route("hello")]
[HttpGet]
public string Hello()
{
   return "Hello there!";
}

Now run your application. Add the `/hello` endpoint in your browser. You’ll be prompted to open a “hello.json” file.

For my setup, this file opens in VS Code and I see “Hello there!” returned.

Configure SSL

  1. Open the Properties Tool Window for the project, i.e. go to View – Properties Window (or press F4 on the project in solution explorer)
  2. Set SSL Enabled to true
  3. Copy the resulting SSL Link that appears below
  4. Go to the Properties page by right clicking on the project name in solution explorer and selecting Properties (or pressing Alt+Enter)
  5. On the Web side-bar tab, paste in the SSL link in the Project Url
  6. Click Create Virtual Directory – this step may be optional, I’m not sure.

Run your project and hit the /hello endpoint just to verify you are all set with SSL.

Now that the API is working properly, we can now move onto the next step: authorizing only those users with certain scopes in their access tokens to access the API.

Register the API in Azure AD B2C

Although you can register the API in the Azure portal at any time, I prefer to create the project first. It just keeps me grounded as to what I’m doing.

  1. Go to the Azure Portal – https://portal.azure.com/
  2. Make sure you are in the correct tenant you want to use.
  3. Register a new Web API
    1. Click Applications –  Add.
    2. Give it a reader-friendly name, like `Hello API for Demo`
    3. Click Yes for Web App / Web API
    4. For Reply URL, paste in the SSL URL you are now using from the Properties page (the Alt+Enter page) along with the endpoint e.g. `https://localhost:44326/hello`
    5. For App ID URI, provide a unique ID, e.g. `helloAPI` – this must be unique across all your B2C-registered applications in your tenant.
    6. Keep Native client as No.
    7. Click Create and wait a couple of seconds.
  4. Add scopes
    1. Click on your newly registered application in the portal, i.e. `Hello API for Demo`
    2. Click Published scopes 
    3. Under Scope, give it the name `read` and a description `yet another read access`

If you have any issues following these steps, please check out my previous blog post.

Install the middleware 

Back to Visual Studio!

The next steps are about setting up the middleware – aka the libraries for the Web API that talk to B2C, parse tokens, etc.

Note: OWIN is a specification, whereas “Katana” is the implementation of OWIN for .NET, but it seems a lot of people say “OWIN” to represent the implementation that is Katana.

You install all the necessary OWIN / Katana packages from the Package Manager Console. The blog post uses the nuget command line.

Note: if you decided to keep it all into one big solution, you’ll need to specify the project name (`Install-Package Microsoft.Owin.Security.OAuth -ProjectName HelloAPI`) or switch to that project in the nuget Package Manager Console dropdown. This got me a few times at first. I didn’t realize I was installing to the wrong project.

1. Run the command

Install-Package Microsoft.Owin.Security.Oauth

This will install at least the following dlls:

  • Owin
  • Microsoft.Owin
  • Microsoft.Owin.Security
  • Microsoft.Owin.Security.Oauth
  • And possibly others

2. Run the command

Install-Package Microsoft.Owin.Security.Jwt

This will install “system.identitymodel.tokens.jwt” – this is a lower layer component that verifies tokens.

3. Run the command

Install-Package Microsoft.Owin.Host.SystemWeb

This loads the OWIN startup.cs into pipeline. Otherwise, you’ll get the dreaded “unauthorized” generic error message.

4. Run the command

Install-Package Microsoft.Owin.Security.OpenIdConnect

This is needed for the OpenIdConnectCachingSecurityTokenProvider class, which is needed for refreshing B2C tokens. You’ll add this class further below.

Add authorization code to the API

To the code!

Next, let’s setup the OWIN middleware.

1. The OWIN middleware needs to be configured at Startup. Otherwise, you’ll get the error:

[EntryPointNotFoundException: The following errors occurred while attempting to load the app.
 - No assembly found containing an OwinStartupAttribute.
 - No assembly found containing a Startup or [AssemblyName].Startup class.

This was a helpful article: OWIN Startup Class Detection

2. At the root project level in Solution Explorer, right-click and Add a new class. Choose OWIN Startup class. Rename the class to Startup.cs

3. Add the following code to the constructor:

// The OWIN middleware will invoke this method when the app starts
public void Configuration(IAppBuilder app)
{
  ConfigureAuth(app);
}

4. Change the class to partial

public partial class Startup

 

5. Go to the App_Start folder and add a new class called OpenIdConnectCachingSecurityTokenProvider.cs. Paste the code from an existing sample. Make sure to change the namespace to match yours. This class is needed to refresh B2C tokens.

6. In the App_Start folder and add a new class called `Startup.Auth.cs`

  • Change this to partial. Why a partial class? It seems to be the design standard I’m seeing other samples use, but there’s no reason you can’t keep it all in the Startup.cs class (not that I’m aware of).
  • Change the namespace from `HelloAPI.App_Start` to `HelloAPI` to match the Startup.cs class
  • Add the following code into your Startup.Auth.cs class to configure the OWIN middleware (notice how this code uses your newly added OpenIdConnectCachingSecurityTokenProvider)
public partial class Startup
{
  // These values are pulled from web.config
  public static string AadInstance = ConfigurationManager.AppSettings["ida:AadInstance"];
  public static string Tenant = ConfigurationManager.AppSettings["ida:Tenant"];
  public static string ClientId = ConfigurationManager.AppSettings["ida:ClientId"];
  public static string SignUpSignInPolicy = ConfigurationManager.AppSettings["ida:SignUpSignInPolicyId"];
  public static string DefaultPolicy = SignUpSignInPolicy;

  /*
  * Configure the authorization OWIN middleware
  */
  public void ConfigureAuth(IAppBuilder app)
  {
    TokenValidationParameters tvps = new TokenValidationParameters
    {
      // Accept only those tokens where the audience of the token is equal to the client ID of this app
      ValidAudience = ClientId,
      AuthenticationType = Startup.DefaultPolicy
     };

     app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions
     {
         // This SecurityTokenProvider fetches the Azure AD B2C metadata &amp;amp;amp;amp; signing keys from the OpenIDConnect metadata endpoint
         AccessTokenFormat = new JwtFormat(tvps, new OpenIdConnectCachingSecurityTokenProvider(String.Format(AadInstance, Tenant, DefaultPolicy)))
     });
   }
}

Now ctrl+. All the things! Or simply just use these using statements in Startup.Auth.cs

using HelloAPI.App_Start;
using Microsoft.Owin.Security.Jwt;
using Microsoft.Owin.Security.OAuth;
using Owin;
using System;
using System.Configuration;
using System.IdentityModel.Tokens;

7. In Web.Config, add the following keys to your <appSettings>

<appSettings>
 <add key="ida:AadInstance" value="https://login.microsoftonline.com/{0}/v2.0/.well-known/openid-configuration?p={1}" />
<add key="ida:Tenant" value="dorfarasB2CTenant.onmicrosoft.com" />
<add key="ida:ClientId" value="b32e98b0-16ec-46ae-9e6a-4ccb0286e9a3" />
<add key="ida:SignUpSignInPolicyId" value="b2c_1_SiUpIn" />

Let’s pause here and make sure everything runs. We just want to make sure the OWIN middleware is configured properly to run at startup.

Add authorization verification to the route

1. In HelloController.cs, add the following constants at the top of the class

 // OWIN auth middleware constants
 public const string scopeElement = "http://schemas.microsoft.com/identity/claims/scope";
public const string objectIdElement = "http://schemas.microsoft.com/identity/claims/objectidentifier";

2. Secure your route by adding the [Authorize] attribute. I got this information from the ASP.NET Web API 2 attribute routing docs.

[Authorize]
[Route("hello")]
[HttpGet]
public string Hello()

3. Add the code to verify the access token contains the correct scopes. And if so, might as well display the name while we’re at it!

public string Hello()
{
   HasRequiredScopes("read");
   string name = ClaimsPrincipal.Current.FindFirst("name").Value;
   return "Hello there! " + name;
}

4. Add the HasRequiredScopes() method below the Hello() method – this is the method the B2C samples are using right now. YMMV.

// Validate to ensure the necessary scopes are present.
private void HasRequiredScopes(String permission)
{
  if (!ClaimsPrincipal.Current.FindFirst(scopeElement).Value.Contains(permission))
  {
     throw new HttpResponseException(new HttpResponseMessage
     {
       StatusCode = HttpStatusCode.Unauthorized,
       ReasonPhrase = $"The Scope claim does not contain the {permission} permission."
     });
  }
}

5. ctrl+. to add `using System.Security.Claims;` for the ClaimsPrincipal object

Let’s run your project to verify everything builds and launches. Don’t try to hit your endpoint yet. You are not authorized yet so it won’t work.

BTW: if someone knows a better way to test everything at this point, please let me know! 
Update: Here’s a new blog post how to test your new API using Postman

Setting up the client to talk to your new API Endpoint

  1. Download or clone the B2C sample WPF project from https://github.com/Azure-Samples/active-directory-b2c-dotnet-desktop
  2. Register this in the Azure Portal (if you’ve already registered this from a previous sample, you can still use that registration)
    1. Make sure you are in the right tenant!
    2. Go to Application – Add
    3. Give your WPF app a friendly name, e.g. ​`​Hello API WPF App`
    4. Click No for Web App / Web API
    5. Click Yes for Native client
    6. Give it a custom Redirect URI of `com.onmicrosoft.<your-tenant-name>.desktopapp://redirect/path`
    7. Click Create
    8. Wait a couple of seconds and open your app Hello API WPF App registration page
    9. Click on API access (preview) then click Add
    10. Select your HelloAPI in the dropdown and make sure the `read` scope is selected
    11. Click OK
  3. In App.xaml.cs
    1. Update the Tenant name to use your tenant name
    2. Update the ClientId to match your Application ID you got from registering your app in the portal
    3. Update your policies to match the ones you’ve created from my previous blog posts.
  4. In App.xaml.cs update the ApiScopes and ApiEndpoint to use you API endpoint and your defined scope, e.g.

 

public static string[] ApiScopes = { "https://dorfarasB2CTenant.onmicrosoft.com/helloAPI/read" };
public static string ApiEndpoint = "https://localhost:44326/hello";

Note: I like to comment out the previous ApiScopes and ApiEndpoint, so in case I need to debug, it’s easy to switch back to a working version.  Note: I like to comment out the previous ApiScopes and ApiEndpoint, so in case I need to debug, it’s easy to switch back to a working version.

5. Run the client app. (Sign out if applicable) and sign in. Now click Call API, and you should see “Hello there! <Display name!>”

Reference

Here’s my API Registration in case it helps you to debug.

Hello API registration in the Azure Portal with Reply URL showing the SSL URL with endpoint and the App ID URI of `helloAPI`

Achievement unlocked: Since I’m historically a client developer, this is my first time blogging about creating an API!

How to review your Azure AD B2C tokens using Policy – Run Now and jwt.ms

On the Policy window, you’ll see this Run Now button at the bottom of the screen.

B2C Sign In or Sign Up Policy window

The Policy – Run Now button opens the URL shown in the Run now endpoint (shown above the button) in a new tab browser. This call to B2C the /authorize endpoint displays the familiar login window.

Sign in with local account screen

Once you successfully login, B2C will send the token (either id_token or access_token) to the selected Reply URL listed on the Policy – Run Now page. If you add `https://jwt.ms` to one of your applications reply URLs, you’ll be able to select it from the dropdown.

Select application and Select reply URL for Policy - Run Now

Recall you can add a reply URL to an application by going to its registration page, e.g. “drofaras B2C web app”, and adding https://jwt.ms to the list of Reply URLs.

Since this example requests an id_token be sent to https://jwt.ms, the following URL is shown in the browser.

https://jwt.ms/#id_token=eyJ0eXAiOiJKV1QiLCJhbGc...

I’ve learned that the # is a Fragment Identifier, so anything after the # can only be used client-side. The website jwt.ms takes this id_token and decodes it for you…

jwt.ms showing decoded

What about access tokens?

Yep, you can also test out access tokens as well as id tokens.

Go back to the Policy settings page and expand the Access Token area. Select the resource, e.g. a Web API, and the desired scopes you want to verify.

specifying access tokens for Policy - Run Now

Clicking run now will open jwt.ms, but nothing will be displayed. The website is only looking for id_tokens. But, if you copy everything after the #access_token in the url

https://jwt.ms/#access_token=eyJ0eXAiOiJKV1QiL...

and paste that in directly to jwt.ms, you’ll see the access token decoded.

Other usages for Run Now

Suppose you’ve made some changes to your policy and you want to verify things are setup the way you want from within the Azure portal. Examples include

  • You’ve added a sign-up claim and you want to verify this claim appears correctly in the id_token.
  • You’ve added a new Social Identity Provider and want to quickly test you can sign in.
  • You’ve added a new scope in the access token and want to verify it in your awaiting server listed in the Reply URL

Note

Something that confused me early on is I tried to test my policy immediately after I created it, meaning that I didn’t have a localhost server up and running yet. When I ran the policy, I got the following

can't reach this page

Now of course this makes sense, since I’d need to have http://localhost:50185 (from image) running… however, I could have still verified my tokens by coping everything from the # token portion of the URL, e.g.

http://localhost:50185/#id_token=eyJ0eXAiOiJKV...

and pasting it into jwt.ms, even though my reply url server isn’t running.

FWIW

At first glance, I thought the Policy – Run Now button meant to “run” the policy as in “Visual Studio F5 Run” the policy – as if creating it, but that’s not what’s happening here. 

At second glance, I thought the Run now button performed more logic behind the scenes, but it is just calling that /authorize endpoint in a new tab. 

 

 

How to use https://jwt.ms/ to decode JSON Web Tokens

tl;dr The site https://jwt.ms allows you to decode tokens and the tokens never leave your browser.

Once I got a handle on what access tokens are used for, the next step became how do I know what is inside an access token? For example, is the app telling me that the user is unauthorized because they are not signed in? Or is it because a scope is missing or contains a typo in the access token?

What’s a JSON Web Token?

From the Azure AD B2C documentation

Many of the tokens that Azure AD B2C issues are implemented as JSON web tokens (JWTs). A JWT is a compact, URL-safe means of transferring information between two parties. JWTs contain information known as claims. These are assertions of information about the bearer and the subject of the token. The claims in JWTs are JSON objects that are encoded and serialized for transmission. Because the JWTs issued by Azure AD B2C are signed but not encrypted, you can easily inspect the contents of a JWT to debug it. Several tools are available that can do this, including jwt.ms. For more information about JWTs, refer to JWT specifications.

> A JWT is a compact, URL-safe means of transferring information between two parties. 

First, a JSON Web Token is a token (i.e. a string of numbers and letters) that when decoded will present data in JSON format.

> JWTs contain information known as claims.

The content that we’re interested in right now is called “claims”. This is terminology that will make sense once you see a JWT decoded.

> The claims in JWTs are JSON objects that are encoded and serialized for transmission. 

Yep, what I said earlier.

> Because the JWTs issued by Azure AD B2C are signed but not encrypted

You’ll see in a bit where the JWT is signed.

What does a JSON Web Token look like in jwt.ms?

Fortunately the documentation contains a couple of different sample JWTs: an id token and an access token. Both are JWTs, but have different “claims” and different purposes.

The differences between an id token and an access token start to make a lot more sense once you see them decoded and compare them.

Let’s start with an id token. Cut and pasting the sample id token from the docs into jwt.ms shows the following:

Color coded JWT token text

Note the text at the bottom of the image “This is an Azure AD B2C token.” The jwt.ms site also figures out if you’ve supplied an Azure AD v1 token or Azure AD v2 token. In the future, this will be important to verify in case your token isn’t being accepted somewhere.

Also the token is color-coded. These colors are represented in the lower half of the screen.

token broken down into color coded JSON sections

The items in blue are the claims. If you click on the Claims tab, you’ll see the descriptions of these claims.

claims descriptions shown

The last item in the list is idp​ meaning the token “claims” to have come from the identity provider facebook.com.

It is common for an id tokens to contain something like a “name” claim which is used to show your Display name after you log in, e.g. “Hi Sara!” The app is getting the Display name from the id token claims.

How does an access token differ from the id token in jwt.ms?

The best way to see the differences is to use the access token generated from my previous blog post.

For example, if I view the access token from my previous blog post, I can see the scopes I specified for access to the API. These scopes are claims for the token.

scp claim showing HelloRead and Hl

This is important because the next time I get an unauthorized access error trying to call an API, I can check whether the access token contains the right scopes.

Remember those “application claims” you checked on your Sign In Or Sign Up policy, e.g. Display Name and Postal Code?

Postal Code checked for Application claims

well, here you go! they are shown as claims.

Display name claim Smo Jo and postalCode claim 98052

There are other claims that are important to know as well. From  https://aka.ms/b2caccesstokens

  1. aud – Audience – The application ID of the single resource that the token grants access to.
  2. azp – Authorized Party – The application ID of the client application that initiated the request.

BTW: SmoJo was my high school nickname, like FloJo, but not as fast =)

 

A Dark Tower inspired guide to getting started with Azure AD B2C

A bit of backstory

I’m a BIG fan of The Dark Tower books (talk to me if you have questions re movie). As a client/mobile app developer, I feel like Roland (the Gunslinger) wandering in a tech world “that has moved on” from client apps to JavaScript.

Stephen King - The Waste Lands Book 3

 

And from what I hear re JavaScript, the chaotic ruins of mid-world is a good analogy =)

In my traditional `saraford` fashion, I’m going to blog what I’m learning on the Azure AD B2C team, just in case it can help someone else. Oh yeah, I’m back at Microsoft!

But more importantly, blogging about what I’m learning ensures that I know the material, forcing me to ask all those embarrassing newbie questions like, “what’s a tenant?”

For the past month, I’ve been heads down learning about Azure AD B2C, what it is and what it is used for. And as client app dev, there’s A LOT of ramping up I have in front of me. A LOT.

Just like my first punch thrown in karate 20 years ago, you just have to start somewhere…

What’s included in this blog post

  1. What’s Azure AD B2C
  2. About the Getting Started Sample
  3. What does this sample do?
  4. Where Azure AD B2C comes in
  5. Creating an Azure AD B2C Tenant
  6. Registering the Web App
  7. Registering the Web API
  8. Defining the permissions / scopes for an API
  9. Giving the Web Application permissions to the API
  10. Creating a “Sign In or Sign Up” policy
  11. To the code!
  12. Run your app
  13. Putting it all together
  14. Go then… there are other policies than these

1.  What’s Azure AD B2C?

You use B2C when you want users to sign up for your apps using their own social identities (e.g. twitter, facebook, etc.) or email addresses (“local account”).

Your users can manage editing their profiles, resetting their passwords, etc. while you can focus on developing your apps instead of learning how to be an Active Directory administrator.

And yes, in the spirit of completeness, there’s a third type where your users can sign-in using a username (another local account type), but let’s skip that for now.

2.  About The Getting Started Sample

This sample is where I had my lightbulb “I get it now” moment, only thanks to a very patient onboarding buddy who didn’t mind explaining Reply URIs and Fiddler several times.

Now I want to share with you all my same lightbulb moment – just to get you up and running with the sample.

If you’re following along at home, go to the .NET Web App and Web API sample and clone.

Note: if you are using GitHub Desktop on Windows with clone location defaults, you’ll need to rename the cloned folders; otherwise, the file paths will be too long.

BTW I’m not discussing the libraries being used (MSAL and OWIN) here. Honestly, I haven’t ramped up on that yet, so stay tuned.

3.  What does this sample do?

This sample is a TODO application. Inside the solution, you’ll find two projects:

  • TaskWebApp – A web application where you can enter your TODOs. (Note: these calls go directly to the web API)
  • TaskService – A web API that manages your TODOS, e.g. all the CRUD operations. The web app simply calls this API and displays what the API returns.

This sample demonstrates using the Sign Up or Sign In policy to create / sign in with an email address. We’ll cover the social identity provider later.

Have I mentioned I’m not a web dev, wandering in a world that has moved on into JavaScript? But I’m changing that starting now!

Here’s how the sample works once we’ve wired it all up.

  1. The user signs up to use the application by clicking the Sign up / sign in link.

ASP.NET Web App as a To-Do List running

2. The user enters his/her information.

Note: I’m demo’ing a “local account” that is, signing up via an email address.

Note: You need to use a valid email address to receive the verification code. That’s just how this sample is configured.

signing up as Roland Deschain

3. The user sees his/her display name (and if you wire-up the entire sample, you’ll get edit profile and reset password working – but for now let’s just get To-Do list working)

Roland Deschain as signed in user

4. Once logged in, the user can click To-do List and enter some Todos.

The To-Do List - Tell Oy! he's a good Oy!

Note: all these CRUD operations are HTTP Requests to the Web API.

4.  Where Azure AD B2C comes in

If you’re like me, you might be wondering, well, why not just have the Web App handle all the CRUD operations? This is an example of how the “world has moved on” while I was PM’ing the last several years. Let’s assume you not only have a Web App, but you also have mobile apps on different devices. All these apps need to talk to the same service, i.e. some Web API, to handle the CRUD operations.

If you’re looking at B2C, it is because you have a service out there and you want your application (client, mobile, web) to consume that service.

Here’s what the diagram looks like. Note this is a “classic Open ID connect flow” which I’m still ramping up on.

High level diagram of who is calling whom

Let’s break this diagram down a bit:

  1. Clicking Sign up / sign in: the user is sent to a login.microsoftonline.com/… page to sign up or sign in.
  2. B2C sends back two items(1) if the login (or sign up) is successful:
    • id_token – this token(2) has info (called claims) about the user, e.g. Display name. The id_token is handed out when the user is who they say they are, i.e. AutheNtication. Note the capped `N` for emphasis.
    • Access token – this token tells the application what permissions, called scopes(3), this user has for whatever registered services.
  3. Web App to Web API: When the Web App calls the Web API, it sends the Web API an access token. The Web API looks at this token and says, “yep, this user has the right permissions (or scopes) to call this API.” Otherwise, if you try to click on the To-do List link without setting up these “scopes”, you’ll get an Unauthorized error message on the website (even though you’re successfully signed in.)
  4. Trust relationship – this really should be item 0. The Web API needs a way to “trust” this access token. Otherwise, it’s just a random string of numbers and letters. This trust relationship with B2C is defined via the portal, which you’ll see further on in this walkthrough. In addition, the web app needs a way to be registered with B2C, which is done via the portal as well(4).

(1)To be more accurate, this is the grant type = authentication code flow, where the browser receives an authorization code, which gets traded for an access token that’s only sent to the browser… but for now for us non-web devs, let’s stay high level.

(2)A token is just a string of numbers and letters. More on tokens later, but for now, just know it is a string that is sent back. And when this string is decoded, you can see things (e.g. Display name, permissions/scopes) inside (called claims). When a token decoded, you can see what permissions (or scopes) are defined (or claimed) within this token. We’ll look at a token in depth in a future blog post. For now, let’s just get this running.

(3)“Scopes” are the official term used inside a token to represent permissions. If you’re looking at a decoded token and see “scopes”, think permissions. And if you’re reading about permissions, think “scopes”. But “scopes” is the official term used in the token.

(4)Anytime “something” needs to talk to B2C, that something has to be registered with B2C, hence why you’ll hear a lot about registering your app or service to B2C. All this registering is done via the Azure portal

Before we jump into registering our applications, let’s find out a bit more about these two projects included in our sample so we know what we’re registering with B2C.

5.  Creating an Azure AD B2C Tenant

Now that we know what our samples will do, we’ll need to first create a B2C Tenant (also known as a Directory). This tenant/directory thingy is the triangle you saw in the above diagram.

If you’ve already have a test B2C Tenant, jump down to the next section. Otherwise, following along!

Follow the directions under the headings

  1. Create an Azure AD B2C tenant and
  2. Easy access to settings

With the caveats:

  1. Don’t worry about Linking to your subscription right now. Everything you need to do to get these samples up and running can be handled without a subscription.
  2. Make sure you follow the Easy access to settings steps, specifically for the “To switch to your Azure AD B2C tenant, select the B2C directory in the top-right corner of the portal.” I missed this the first time, and I was totally confused why I didn’t have admin rights. The reason was that I was signed in using my microsoft.com email address, so I didn’t have admin rights to the overall Microsoft company directory =P
  3. For the Organization name and Initial domain name, instead of `Contoso`, use <Your Fictitious Test Company Name>. The Initial domain name must be unique across the board since it is the unique identifier for a directory.

 

Contoso Tenant name already in use by another directory

Now your B2C tenant should be all ready to go, but let’s first talk about these applications (the Web App and Web App) we’re about to register.

6.  Registering the Web App

What the Web App does

This is our web app. Notice it is running on https://localhost:44316

  • The To-Do List link calls the Web API (the other project in the solution)
  • There’s a Sign-up or Sign-in link to the far right. The user needs to be signed in to access data from the Web API. (In theory, each user is accessing his/her own todo list.)

The To-Do List link calls the Web API

What to tell B2C about the Web App

To tell B2C about your Web App, you’ll need to register your Web App with B2C via the Azure portal. Make sure you’re in your B2C tenant in the upper right drop-down.

List of your directories

There are step by step directions for registering an application but here’s the resulting screenshot for this particular Web App sample. I bold Web App as to not confuse with Web API project.

line by line description of the app registration page

To recap the screenshot above:

  • Name – for you as a human to identify your app in the Azure portal
  • Application ID – what you’ll copy into the sample application
  • Web App / Web API – yes, we’re registering a Web App
  • Reply URL – use https://locahost:44316 since this is what the Web App sample is using when you run it locally. This is needed for B2C to know where to send the access token to. (I’m not a web developer yet, so just go with this that this magically works.)
  • App ID URI – leave this blank. We’ll use this when we register our Web API.

Getting the Client Secret

When you first want to talk to B2C from your Web App, you need to send it the Client ID (aka the Application ID as shown in the portal) and the Client Secret. It’s kinda like “I am who I say I am, and here’s the Client secret to prove it.” These client credentials are sent via the HTTP request in the Web App during the initial `/authorize` endpoint call, kicking off the rest of the authorization flow. You’ll see where to add these in the code later in this walkthrough.

To get your Web App client secret, go to the Keys page for your Web App registration.

General - Keys link

Note: when you click Generate key, you’ll only get to see it this one time. Make sure you copy it down somewhere if you’re not ready yet to paste into Visual Studio.

7.  Registering the Web API

Now that the Web App is registered (although we’re not completely done yet – more later), let’s go register the Web API.

Here’s what the resulting screenshot should look like:

line by line description of registering an API w B2C

To recap the above screenshot:

  • Name – for you to identify your Web API in the Azure portal
  • Application ID – to put into your code
  • Web App / Web API – yep, we’re a Web API
  • Reply URL – this is the localhost:port the sample uses.
  • App ID URL – This is needed for the Web API to tell B2C, “Hey I want an access token (with these scopes*) for this particular API because a tenant could have more than 1 registered API. But scopes are only defined for a particular API. In other words, scopes are not global to a tenant.

*This got me thinking: could you have an access token without scopes? I guess so (and I’m sure I created one or two accidentally when I first got started), but then it would be like saying, “here’s a driver’s license card, but just the physical blank card your driver’s license would have been printed on.” Sure, you’d have a card, but it wouldn’t get you far.

This Web API registration also defines the trust relationship. Since the API is now registered with B2C, it can now “trust” access tokens sent to it from B2C.

8.  Defining the permissions / scopes for an API

Now we’ve printed out a “blank driver’s license.” Now to add some content or permissions (or scopes) to be contained within our access token.

Still within the Web API registration, click on Published scopes (Preview)

General - API Access - Published scopes

And fill out your scopes as shown below.

How scopes are defined

Why the “Hello”? No idea. This was just the example I learned. But the main takeaway is the Scope field is the name of the scope / permission that will appear in the token and also that you’ll use in your code.

9.  Giving the Web Application permissions to the API

Alrighty. What we’ve done above is say, “Hey (mid-)world! This API will have the following permissions: Read, Write.” I guess you could have also added a permission called, “WriteOnly” or “SaraNoH” that only allows read access to Sara’s who don’t have an ‘h’ in her name. The point is that you get to define the permissions / scopes for your API.

Next, we’ll tell B2C which scopes the Web App has permissions to use.

Switch over to your Web App in the Portal and click API access (Preview)

General - API access - API access Link

Now click Add at the top. A window appears on the far right hand side.

You’ll want to select your Web API by it’s human-identifiable portal name and select the scopes you just created in the Web API registration.

Selecting the desired scopes to be used by the web app

And make sure you click ok at the bottom!

Ok button

Now your Web App and Web API should be registered properly with B2C.

Lastly, before we can leave the Azure Portal, we need to create a “policy” – i.e. how you want your users to sign up for your apps.

10.  Creating a “Sign In or Sign Up” policy

Follow the steps listed under the header: Create a Sign in or Sign up policy.

A few things I missed the first time:

  • Sign up attributes – these are the fields your users will see when they sign up for your app
  • Application claims – these are the “claims” that will appear in your token. For now, just make sure that you check User is new and User’s Object ID. I missed those the first time.
  • Call the policy b2c_1_SiUpIn. This is the name I use the same in the code samples below (just in case the policy name in GitHub gets changed at any point). Also I’m not 100% certain if policy names are case sensitive, but I’ll find out.
  • For the Select reply url, note that you’ll need to select the application first.

selecting application to define the reply url

Optional: You can click Run Now if you want to verify you can sign up for your app. But it won’t do much. You’ll need to go to the main tenant page and check under Users and Groups to verify (I believe – I’m still learning).

11.  To the code!

Now that the Web App and Web API are registered with B2C and you have a policy, it’s time to wire-up the samples to talk to your B2C tenant.

Open the B2C-WebAPI-DotNet solution in Visual Studio.

Note: By default, the samples are wired-up to talk to a demo tenant called `fabrikamb2c.onmicrosoft.com` To have these samples talk to your specific tenant, you’ll want to update the Web.config for both projects.

BTW: you can go to Tools – Options – Projects and Solutions – General page and check the Track Active Item in Solution Explorer to keep track of which Web.config you are editing.

In the TaskWebApp project, open the Web.config file:

1. Make the following updates:

<add key="ida:Tenant" value="<Your Fictitious Test Company Name>.onmicrosoft.com" />

<add key="ida:ClientId" value="<The Application ID for your Web App as seen in portal" />

<add key="ida:ClientSecret" value="the Web App secret - if you didn't copy it, delete and regenerate" />

 

2.  Update the value with the value you used to create your policy. If you’re following along this example, use the value below

<add key="ida:SignUpSignInPolicyId" value="b2c_1_SiUpIn" />

3.  Comment out the aadb2cplayground site and uncomment the `locahost:44332` for the TaskServiceUrl – this will be the localhost port for the Web API to run on. Your code should look like the following below.

 

<!--<add key="api:TaskServiceUrl" value="https://aadb2cplayground.azurewebsites.net/" />-->

<add key="api:TaskServiceUrl" value="https://localhost:44332/"/>

4.  Give the App ID URI of the API to the Web App so it can tell B2C which API it wants permissions to by commenting out the fabrikamb2c tenant and updating your scopes as follows:

<!--<add key="api:ApiIdentifier" value="https://fabrikamb2c.onmicrosoft.com/api/" />—>

<add key="api:ApiIdentifier" value="https://dorfarasB2CTenant.onmicrosoft.com/api/" />

<add key="api:ReadScope" value="HelloRead" />

<add key="api:WriteScope" value="HelloWrite" />

Next, in the TaskService project, open the Web.config

1. Make the following changes:

<add key="ida:Tenant" value="<Your Fictitious Test Company Name>.onmicrosoft.com" />

<add key="ida:ClientId" value="<The Application ID for your Web API as seen in portal>"/>

2.  Update the value with the value you used to create your policy. If you’re following along this example, use the value below

<add key="ida:SignUpSignInPolicyId" value="b2c_1_SiUpIn" />

3.  Update your scopes as follows:

<add key="api:ReadScope" value="HelloRead" />

<add key="api:WriteScope" value="HelloWrite" />

And that’s it! Well almost…

12.  Run your app

You’ll need to run both the Web App and the Web API at the same time. You can do this by configuring the Solution – Startup Project to run both at the same time, e.g.

Change None to Action for both projects under Multiple Startup Projects

I love finding out new stuff about Visual Studio! I don’t know how I didn’t know about this back in the day, or maybe it wasn’t available back then. /shrugs

You should now be able to perform the scenarios discussed at the start of this blog post that you began reading 20 years ago =) What can I say? I just like to write!

  1. Go to the Web App (that’s the website on http://localhost:44316) and click the Sign In / Sign Up button to sign up.
  2. Once signed in, click on the To-Do list link.

If all goes well, you’ll be able to edit your own todo list. If things don’t go well, (cry your pardon sai), leave a comment below. I’m putting together a FAQ of what the different sort of error messages look like when putting together this sample.

Old SDET habits never die.

13.  Putting it all together

Something that would have helped me out big time at the beginning would have been the following diagram to see how the Azure portal App registration fields come into play.

Final diagram showing reply URL, App ID URI, etc.

 

14.  Go then… there are other policies than these

We only looked at the Sign Up or Sign In policy. There are other policies for other things, like resetting passwords, editing a profile, etc. which we’ll get to at another time.

https://docs.microsoft.com/en-us/azure/active-directory-b2c/active-directory-b2c-reference-policies

And yes, I really love The Dark Tower, movie, book, comics. Seriously if you have any questions about the movie, I’m here for ya!