Smartersoft.Azure.WebJobs.Extensions.Jwt
0.1.5-beta0010
See the version list below for details.
dotnet add package Smartersoft.Azure.WebJobs.Extensions.Jwt --version 0.1.5-beta0010
NuGet\Install-Package Smartersoft.Azure.WebJobs.Extensions.Jwt -Version 0.1.5-beta0010
<PackageReference Include="Smartersoft.Azure.WebJobs.Extensions.Jwt" Version="0.1.5-beta0010" />
paket add Smartersoft.Azure.WebJobs.Extensions.Jwt --version 0.1.5-beta0010
#r "nuget: Smartersoft.Azure.WebJobs.Extensions.Jwt, 0.1.5-beta0010"
// Install Smartersoft.Azure.WebJobs.Extensions.Jwt as a Cake Addin #addin nuget:?package=Smartersoft.Azure.WebJobs.Extensions.Jwt&version=0.1.5-beta0010&prerelease // Install Smartersoft.Azure.WebJobs.Extensions.Jwt as a Cake Tool #tool nuget:?package=Smartersoft.Azure.WebJobs.Extensions.Jwt&version=0.1.5-beta0010&prerelease
Smartersoft.Azure.WebJobs.Extensions.Jwt
Azure Functions is great for creating an api easily, we felt it was missing support for JWT authentication. So we build this small extension to get jwt support backed by OpenID connect discovery for automatic key rollover.
We build this to support Azure AD, you can however use it with whatever identity provider as long as it supports OpenID connect (which I'm sure all do these days).
This library is created by Smartersoft B.V. and licensed as GPL-3.0-only.
Getting started
Create new Azure Functions or use an existing one. This package supports net7.0
, net6.0
and netcoreapp3.1
.
Add packages Smartersoft.Azure.WebJobs.Extensions.Jwt
to your project.
Project file changes
Add the following line to your Functions project file.
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<AzureFunctionsVersion>v4</AzureFunctionsVersion>
<_FunctionsSkipCleanOutput>true</_FunctionsSkipCleanOutput>
</PropertyGroup>
Required configuration
Add this information to your local.settings.json
file replace the fields accordingly:
"JWT__Authority": "https://login.microsoftonline.com/{your-tenant-id}/v2.0",
"JWT__ValidAudiences__0": "{application-id}",
"JWT__ValidAudiences__1": "api://{application-id-as-app-uri}",
You can replace {your-tenant-id}
with organizations
to support all organizations. For single tenant usage be sure to also add:
"JWT__ValidIssuers__0": "https://login.microsoftonline.com/{your-tenant-id}/v2.0",
These properties are in the JWT
configuration section (because of the double underscores), and will be needed in the Startup file.
The configuration will be downloaded from {Authority}/.well-known/openid-configuration
.
Startup file
This library extends the Azure Functions, follow use DI in .NET Azure Functions to set up Dependency injection correctly.
Add the following to your startup file:
using Microsoft.Azure.Functions.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection;
using Smartersoft.Azure.WebJobs.Extensions.Jwt;
[assembly: FunctionsStartup(typeof(Startup))]
public class Startup : FunctionsStartup
{
public override void Configure(IFunctionsHostBuilder builder)
{
...
builder.AddOpenIdConnectTokenValidator();
// or if you changed the Authentication section name to Auth
// builder.AddOpenIdConnectTokenValidator("Auth");
...
}
}
WebJobs extension
Create a StartupWebJobs
class, with the following content:
using Microsoft.Azure.WebJobs.Hosting;
using Microsoft.Azure.WebJobs;
using Smartersoft.Azure.WebJobs.Extensions.Jwt;
[assembly: WebJobsStartup(typeof(StartupWebJobs))]
public class StartupWebJobs : IWebJobsStartup
{
public void Configure(IWebJobsBuilder builder)
{
builder.AddTokenValidatorExtension();
}
}
Azure AD configuration
- Create an app registration for your API guide
- Expose a scope for your api guide (for delegated permissions)
user_impersonation
in this sample. - Add app roles for you API guide (for application permissions)
Read.All
in this sample - Create a client application to get tokens with.
Tokens in a delegated (user) flow, will only be given out once consent is given.
Token in an application flow, will be given to any application in the tenant, even if they are not granted admin consent. These tokens will however not contain any role, which is why it's really important to verify at least a scope or a role. This library enforces that, we don't want you to become vulnerable to incorrect configuration attacks.
Validate tokens
Add [TokenValidator(Scopes = "user_impersonation")] TokenResult token
to your function. And use this code to return an error:
if (token.Status != TokenStatus.Valid)
{
return token.GetFaultyActionResult();
}
Validate tokens NOTE
We know this is not ideal since having to verify the token in each function has several down-sides:
- Developer can forget to check the token, make sure you test all your endpoints for this!
- You can forget to emit a faulty result.
We use this way because of the following reasons:
- This gives you total control on what statuscode to emit.
- You can use all the details in the token right in your application.
- The correct error code shows up in the Azure Functions logging.
An other way would be trowing an exception upon a faulty or missing token, but since those would then be binding errors it would throw a 500
error because a value could not be bound correctly. And you cannot catch binding errors in Azure functions.
Sample function
using System.Net;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.Azure.WebJobs.Extensions.OpenApi.Core.Attributes;
using Microsoft.Extensions.Logging;
using Microsoft.OpenApi.Models;
using Smartersoft.Azure.WebJobs.Extensions.Jwt;
namespace MyFunctions;
public class CheckTokenFunction
{
private readonly ILogger<CheckTokenFunction> _logger;
public CheckTokenFunction(ILogger<CheckTokenFunction> log)
{
_logger = log;
}
[FunctionName("CheckTokenFunction")]
[OpenApiOperation(operationId: "Run", tags: new[] { "name" })]
[OpenApiResponseWithBody(statusCode: HttpStatusCode.OK, contentType: "text/plain", bodyType: typeof(string), Description = "The OK response")]
public async Task<IActionResult> Run(
[HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = null)]HttpRequest req,
[TokenValidator(Scopes = "user_impersonation")] TokenResult token)
{
_logger.LogInformation("C# HTTP trigger function processed a request.");
if (token.Status != TokenStatus.Valid)
{
return token.GetFaultyActionResult();
}
// Use details from the token
string name = token.DisplayName;
string responseMessage = $"Hello, {name}. This HTTP triggered function executed successfully.";
return new OkObjectResult(responseMessage);
}
}
License
These packages are licensed under GPL-3.0
, if you wish to use this software under a different license. Or you feel that this really helped in your commercial application and wish to support us? You can get in touch and we can talk terms. We are available as consultants.
Product | Versions Compatible and additional computed target framework versions. |
---|---|
.NET | net5.0 was computed. net5.0-windows was computed. net6.0 is compatible. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 is compatible. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 was computed. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. |
.NET Core | netcoreapp3.1 is compatible. |
-
.NETCoreApp 3.1
- Microsoft.Azure.Functions.Extensions (>= 1.1.0)
- Microsoft.Azure.WebJobs (>= 3.0.33)
- Microsoft.Extensions.Http (>= 3.1.31)
- Microsoft.Extensions.Options (>= 3.1.31)
- Microsoft.IdentityModel.Protocols.OpenIdConnect (>= 6.25.0)
-
net6.0
- Microsoft.Azure.Functions.Extensions (>= 1.1.0)
- Microsoft.Azure.WebJobs (>= 3.0.33)
- Microsoft.Extensions.Http (>= 6.0.0)
- Microsoft.Extensions.Options (>= 6.0.0)
- Microsoft.IdentityModel.Protocols.OpenIdConnect (>= 6.25.0)
-
net7.0
- Microsoft.Azure.Functions.Extensions (>= 1.1.0)
- Microsoft.Azure.WebJobs (>= 3.0.33)
- Microsoft.Extensions.Http (>= 7.0.0)
- Microsoft.Extensions.Options (>= 7.0.0)
- Microsoft.IdentityModel.Protocols.OpenIdConnect (>= 6.25.0)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
Version | Downloads | Last updated |
---|---|---|
0.1.5-beta0017 | 86 | 4/14/2024 |
0.1.5-beta0016 | 83 | 1/23/2024 |
0.1.5-beta0011 | 199 | 11/9/2022 |
0.1.5-beta0010 | 137 | 11/9/2022 |