Azure AD authentication in Blazor using ADAL.js
Although Blazor is in early stages of development it is already good enough to try out and play with it. As a logical continuation to my previous experiment where I made Blazor application use Azure Functions based back-end I made it also support Azure AD authentication on web application and back-end level. This blog post introduces my work on Blazor and Azure AD.
Source code available! Source code for this post is available in my GitHub repository gpeipman/BlazorDemo. I expect you to keep the code open while going through this blog post. Where adequate I also have links to specific files in solution provided.
Warning! This solution is not something final or permanent. It is proof-of-concept level solution with known issues on both sides – my and Blazor side. If you know solutions to most common problems here then please feel free to add your ideas to comments section of this post.
Problem and solution
As Blazor is browser-based technology we can think about it as a neighbour of JavaScript. Although Blazor is very young technology in its early phases it already supports JavaScript interoperability. We can call JavaScript functions from Blazor and C# functions from JavaScript. For JavaScript we have millions of libraries available and one of these supports Azure AD: Active Directory Authentication Library (ADAL) for JavaScript.
ADAL library takes automatically care of tokens but it doesn’t come easy as there is method with callback involved. It means that we cannot just have one function in JavaScript that returns valid token. Instead we have to call method, provide it with callback where token is given and then we can get back to Blazor. In Blazor it means I have to delay my requests for data until I get back valid token.
It leads us to some ping-pong between Blazor and JavaScript.
I managed to make this flow work. There are sometimes JavaScript errors probably because of threading issues. From Blazor issue tracker I found out that Blazor team is aware of this problem and they will target it in future releases.
Preparing and configuring infrastructure
Before we start coding we need all pieces of solution to be set up and configured. The following diagram gives a high level overview about what needs to be done to mimic my solution.
I don’t stop here but give references to materials that help you to set up similar environment.
- Introducing static website hosting for Azure Storage (Gunnar Peipman)
- Hosting Azure Functions backed Blazor application on Azure Storage static website (Gunnar Peipman)
- ADAL JavaScript library and Azure AD Javascript Getting Started sample (Microsoft)
- Securing Azure Functions with Azure Active Directory – Part 2 (Pete Skelly)
- Configure your App Service app to use Azure Active Directory login (Microsoft)
Using ADAL JavaScript library
ADAL JavaScript library is one JavaScript file. We include it in index.html file (under wwwroot folder). This library provides us with everything needed to communicate with Azure AD.
<script type="blazor-boot">
</script>
<script src="https://code.jquery.com/jquery-3.3.1.min.js" integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8=" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js" integrity="sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q" crossorigin="anonymous"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js" integrity="sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl" crossorigin="anonymous"></script>
<script src="//static.gunnarpeipman.com/js/adal.js"></script>
<script src="//static.gunnarpeipman.com/js/app.js"></script>
app.js is a file where I have all Azure AD and UI related JavaScript code. We configure ADAL authentication context first and then handle the situation when browser was redirected back from Azure AD login page. Finally we check if user is authenticated and if not then we send him or her to Azure AD login page.
var authContext = null;
var user = null;
(function () {
window.config = {
instance: 'https://login.microsoftonline.com/',
tenant: '<Your tenant URL>',
clientId: <Your application ID>',
postLogoutRedirectUri: window.location.origin,
cacheLocation: 'localStorage' // enable this for IE, as sessionStorage does not work for localhost.
};
authContext = new AuthenticationContext(config);
var isCallback = authContext.isCallback(window.location.hash);
authContext.handleWindowCallback();
//$errorMessage.html(authContext.getLoginError());
if (isCallback && !authContext.getLoginError()) {
window.location = authContext._getItem(authContext.CONSTANTS.STORAGE.LOGIN_REQUEST);
}
user = authContext.getCachedUser();
if (!user) {
authContext.login();
}
}());
// Skipped some UI related functions
Blazor.registerFunction('executeWithToken', (action) => {
authContext.acquireToken(authContext.config.clientId, function (error, token) {
let tokenString = Blazor.platform.toDotNetString(token);
const assemblyName = 'BlazorDemo.AdalClient';
const namespace = 'BlazorDemo.AdalClient';
const typeName = 'AdalHelper';
const methodName = 'RunAction';
const runActionMethod = Blazor.platform.findMethod(
assemblyName,
namespace,
typeName,
methodName
);
Blazor.platform.callMethod(runActionMethod, null, [
action, tokenString
]);
});
return true;
});
executeWithToken() is function known to Blazor. Here you can see why we need a magic described above. authContext.acquireToken() method may make call to Azure AD. On JavaScript calls to other servers are asynchronous but we can usually define callback function that is called when function is done its work. In callback function we have get valid Azure AD token and we send it to Blazor with action we sent from Blazor to executeWithToken() method.
Okay, it gets confusing, I know, but it gets clear for the end of this blog post.
Delaying data binding in Blazor
Before focusing to how to run the action we need one from Blazor. In demo application I have Index.cshtml page where books table is filled. If we don’t have JavaScript callbacks on our way then we can go with simple version of LoadBooks() method like shown here.
private async Task LoadBooks(int page)
{
Books = await BooksClient.ListBooks(page);
}
When ADAL is involved it doesn’t go so easily. We need bearer token to call Azure Functions based back-end that is protected by Azure AD. Here is the ADAL JavaScript version of same Blazor method (code-behind file of Index.cshtml in my demo project).
private void LoadBooks(int page)
{
Action<string> action = async (token) =>
{
BooksClient.Token = token;
Books = await BooksClient.ListBooks(page);
StateHasChanged();
};
RegisteredFunction.InvokeUnmarshalled<bool>("executeWithToken", action);
}
As we don’t have bearer token available when LoadBooks() method is called we create the action where token is given in. Then we use the token with BooksClient instance and ask list of books from back-end Azure Function. Finally we notifiy Blazor that UI must be rendered again as something changed. Notice that this action is not run immediately. It is on-hold until it is actually called somewhere in C# code.
InvokeUnmarshalled() method calls JavaScript function executeWithToken() and provides action as an argument. We must use unmarshalled version of Invoke() method here because it is giving arguments in by reference. Invoke() method would end up with error because it will serialize all arguments to JSON and if it is not possible then exception is thrown.
Invoking Blazor action in token refreshing callback
When ADAL has successfully found bearer token for us our JavaScript function executeWithToken() runs its callback that invokes RunAction() method in Blazor.
Blazor.registerFunction('executeWithToken', (action) => {
authContext.acquireToken(authContext.config.clientId, function (error, token) {
let tokenString = Blazor.platform.toDotNetString(token);
const assemblyName = 'BlazorDemo.AdalClient';
const namespace = 'BlazorDemo.AdalClient';
const typeName = 'AdalHelper';
const methodName = 'RunAction';
const runActionMethod = Blazor.platform.findMethod(
assemblyName,
namespace,
typeName,
methodName
);
Blazor.platform.callMethod(runActionMethod, null, [
action, tokenString
]);
});
return true;
});
Right now we can only call static methods of Blazor classes but it is okay for us. So, here is my action runner implemented as a class on Blazor. All it does is it runs the action provided and gives token in.
public static class AdalHelper
{
public static async Task RunAction(Action<string> action, string token)
{
await Task.Run(() => action(token));
}
}
For some reason using Task was the only way how I got this action to run.
Wrapping up
Although it is not yet supported scenario we were able to make Blazor support Azure AD authentication for web application and Azure Functions based back-end service. This is proof-of-concept style solution where not all scenarios for JavaScript interop are supported yet. But it still good showcase about how to use newest Microsoft technologies to build modern eneterprise applications.
Pingback:Dew Drop - July 9, 2018 (#2761) - Morning Dew
Pingback:The Morning Brew - Chris Alcock » The Morning Brew #2622
Is ADAL.js can be used in local intranet Active Directory server?
AFAIK it is for Azure AD only.
If you’re swiping on courting apps whereas spending time together, then that’s not going to bode nicely for you. When your date looks again on your time together, she may remember it more fondly than she would have if you didn’t smell good. It could not hassle some individuals to be a rebound. Furthermore, speaking about your ex makes it appear that you haven’t gotten over them, which can make the person you’re with feel like a rebound. They also have an English version so will probably be easy for you to make a profile. However, it will still result in an abundance of profiles as there are over 400,000 individuals registered on the web site. Doing it will create a deeper degree of understanding between you and your Ukrainian date. When the question is raised about relationship, in fact the selection to pick out the Ukrainian girls deserves your first precedence.
This is precisely why dating Ukrainian women is a good idea – they make excellent wives and life companions. Ukrainian society places a excessive value on family, and that is reflected within the nation’s dating customs. When you speak about how much cash you may have or how high your salary is or how diversified your stock portfolio is or the rest that implies that you’ve got numerous wealth, then you’re going to make a extremely robust implication of the exact sort. Having too much fun might compel you to behave in a way that’s ungentlemanly. It will be the form of thing that makes the girl that you’re with decide to chop her losses and go away. You and the girl that you are with are purported to have fun with one another. The endgame of the date is for the each of you to have an excellent time.
So have an acceptable quantity of fun, have a couple of drinks and eat some good food. It is possible to date for enjoyable, but that noncommittal attitude shouldn’t be always prevalent in long-distance relationships. So smelling good on a date could make it higher, in a retroactive sense. That’s not good. It will be important to notice that some individuals tend to rant, and ranting might be a serious turnoff. The positioning could also be an excellent one to strive if you’re new to on-line courting and don’t know a lot about Russian ladies. A relationship is ideally a two-method street (give and take), and a date is very like that. Once you offend a Ukrainian on a date, you may make sure that that date is the final one. The primary and most essential step to dating Ukrainian women is data gathering. Most Ukrainian dating websites are plagued with rip-off ladies, so watch out on websites, including Ukrainian Singles.
Resilience and adaptableness – charmdate review As a result of Ukraine’s complicated history, together with periods of battle and alter, Ukrainian folks are sometimes resilient and adaptable. Ukrainian ladies are standard worldwide brides as a consequence of their robust family values, intelligence, schooling, magnificence, and highly effective personalities. Overall, this Ukrainian dating site is professional, dependable, and interesting. Diving into Ukrainian dating? A single Ukrainian woman doesn’t wish to feel like an afterthought on a date. However, when you are on a date, you could have to concentrate to the date. However, conversation is a delicate course of. However, journalism was his last selection. While single Ukrainian women in Ottawa, having a giant selection of males and spoiled by the attention, don’t hurry up to start out critical relations. With their wonderful track report, BeHappy2Day is a great place to begin courting online. Based on their experiences, I can confirm that their relationship experiences are vastly totally different from courting someone without children. She could get the impression that you are playing games along with her and she’s going to resolve that she should be with someone who is able to commit and never play around.
gunnarpeipman.com
gunnarpeipman.com