Helpers for Azure Functions. The library provides FunctionRunContext types that expose user or application identity, UPN, roles, authentication state, request payload parsing, and local development detection.
Package: WebGate.Azure.FunctionsUtils
License: Apache-2.0
dotnet add package WebGate.Azure.FunctionsUtils| Target Framework | net10.0 |
| Package version | 10.x.x |
The NuGet package major version matches the .NET target framework major version.
net10.0→ package version10.x.x- Future uplifts follow .NET LTS releases only (e.g. the next LTS after .NET 10); the package major then matches that TFM major.
Within a major line, use minor/patch for library changes that stay on the same TFM.
Local vs cloud is controlled by one setting:
| Variable | Value | Effect |
|---|---|---|
FUNCTIONS_UTILS_LOCAL_DEVELOPMENT |
true |
IsDev() == true, Bearer JWT allowed |
| unset / other | — | Cloud mode: Easy Auth only, no Bearer |
Set it only in local.settings.json. Do not set it in Azure App Settings.
{
"Values": {
"FUNCTIONS_UTILS_LOCAL_DEVELOPMENT": "true",
"FUNCTIONS_UTILS_AAD_TENANT_ID": "{tenant-id}",
"FUNCTIONS_UTILS_AAD_AUDIENCE": "api://{api-app-id}"
}
}Do not use AZURE_FUNCTIONS_ENVIRONMENT for this — Core Tools overwrites it to Development.
Headers alone are not trusted. Protect cloud Function Apps like this:
Internet → Azure API Management (validate-jwt) → Function App (Easy Auth Required) → UserFunctionRunContext
-
Easy Auth required (cloud)
Enable App Service Authentication / Easy Auth and set unauthenticated requests to Return HTTP 401. WithoutFUNCTIONS_UTILS_LOCAL_DEVELOPMENT, this library accepts only Easy Auth (x-ms-client-principal). -
Do not expose the Function App publicly
Prefer private networking and put Azure API Management in front withvalidate-jwt. -
Bearer JWT (local only)
WhenFUNCTIONS_UTILS_LOCAL_DEVELOPMENT=trueand Easy Auth is absent,Authorization: Beareris validated (signature, issuer, audience, lifetime) via Entra OpenID metadata.Variable Purpose FUNCTIONS_UTILS_AAD_TENANT_IDEntra tenant ID FUNCTIONS_UTILS_AAD_AUDIENCEAPI audience (GUID or api://{app-id}; both accepted)If tenant/audience are missing, Bearer fails closed. The SPA must send an API access token (Expose an API), e.g. MSAL scope
api://{clientId}/access_as_user.
Public entry points:
| Type | Purpose |
|---|---|
UserFunctionRunContext |
User identity from HTTP request headers |
AppFunctionRunContext |
Application identity from explicit id and roles |
IFunctionRunContext |
Shared API for identity, roles, payload, and environment |
Shared API (IFunctionRunContext):
GetUserId(),GetUPN(),IsAuthenticated(),IsDev()IsInAtLeastOneRole(...),IsInAllRoles(...)GetPayLoad<T>()— reads JSON body from the associatedHttpRequest(user context only)GetEnvironmentVariable(name)
UserFunctionRunContext also exposes GetClaimsPrincipal().
IsDev() is true when FUNCTIONS_UTILS_LOCAL_DEVELOPMENT is enabled.
Identity is resolved in this order:
- Azure Easy Auth payload from
x-ms-client-principal(all environments) - Validated JWT from
Authorization: Bearer <token>(only whenFUNCTIONS_UTILS_LOCAL_DEVELOPMENT=true)
Claim mapping:
| Field | Claims (first match wins; roles collect all matches) |
|---|---|
| User ID | oid, Easy Auth object identifier URI, sub, name identifier URI |
| UPN | upn, Easy Auth UPN URI, preferred_username, unique_name, email |
| Roles | roles, http://schemas.microsoft.com/ws/2008/06/identity/claims/role |
Local Bearer JWTs keep short claim names (MapInboundClaims = false) so they align with Easy Auth. The long role URI remains a fallback.
Authenticated is true when a user ID was resolved.
[Function("MyCoolFunction")]
public async Task<IActionResult> MyCoolFunction(
[HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = "users/me")] HttpRequest req)
{
var context = new UserFunctionRunContext(req);
if (!context.IsAuthenticated())
{
return new UnauthorizedResult();
}
var userId = context.GetUserId();
return new OkObjectResult(userId);
}Use for non-user / application callers. Pass application id and roles explicitly; no HTTP headers are parsed.
var context = new AppFunctionRunContext(applicationId, roles: ["reader"]);
var appId = context.GetUserId();