title | description | services | author | ms.service | ms.topic | ms.date | ms.author | ms.custom |
---|---|---|---|---|---|---|---|---|
Accessing user information in Azure Static Web Apps |
Learn to read authorization provider-returned user data. |
static-web-apps |
craigshoemaker |
static-web-apps |
conceptual |
04/09/2021 |
cshoe |
devx-track-js |
Azure Static Web Apps provides authentication-related user information via a direct-access endpoint and to API functions.
Many user interfaces rely heavily on user authentication data. The direct-access endpoint is a utility API that exposes user information without having to implement a custom function. Beyond convenience, the direct-access endpoint isn't subject to cold start delays that are associated with serverless architecture.
Client principal data object exposes user-identifiable information to your app. The following properties are featured in the client principal object:
Property | Description |
---|---|
identityProvider |
The name of the identity provider. |
userId |
An Azure Static Web Apps-specific unique identifier for the user.
|
userDetails |
Username or email address of the user. Some providers return the user's email address, while others send the user handle. |
userRoles |
An array of the user's assigned roles. |
claims |
An array of claims returned by your custom authentication provider. |
The following example is a sample client principal object:
{
"identityProvider": "github",
"userId": "d75b260a64504067bfc5b2905e3b8182",
"userDetails": "username",
"userRoles": ["anonymous", "authenticated"],
"claims": [{
"typ": "name",
"val": "Azure Static Web Apps"
}]
}
You can send a GET
request to the /.auth/me
route and receive direct access to the client principal data. When the state of your view relies on authorization data, use this approach for the best performance.
For logged-in users, the response contains a client principal JSON object. Requests from unauthenticated users returns null
.
Using the fetch1 API, you can access the client principal data using the following syntax.
async function getUserInfo() {
const response = await fetch('/.auth/me');
const payload = await response.json();
const { clientPrincipal } = payload;
return clientPrincipal;
}
console.log(getUserInfo());
The API functions available in Static Web Apps via the Azure Functions backend have access to the same user information as a client application. While the API does receive user-identifiable information, it does not perform its own checks if the user is authenticated or if they match a required role. Access control rules are defined in the staticwebapp.config.json
file.
Client principal data is passed to API functions in the x-ms-client-principal
request header. The client principal data is sent as a Base64-encoded string containing a serialized JSON object.
The following example function shows how to read and return user information.
module.exports = async function (context, req) {
const header = req.headers['x-ms-client-principal'];
const encoded = Buffer.from(header, 'base64');
const decoded = encoded.toString('ascii');
context.res = {
body: {
clientPrincipal: JSON.parse(decoded),
},
};
};
Assuming the above function is named user
, you can use the fetch1 browser API to access the API's response using the following syntax.
async function getUser() {
const response = await fetch('/api/user');
const payload = await response.json();
const { clientPrincipal } = payload;
return clientPrincipal;
}
console.log(await getUser());
In a C# function, the user information is available from the x-ms-client-principal
header which can be deserialized into a ClaimsPrincipal
object, or your own custom type. The following code demonstrates how to unpack the header into an intermediary type, ClientPrincipal
, which is then turned into a ClaimsPrincipal
instance.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Claims;
using System.Text;
using System.Text.Json;
using Microsoft.AspNetCore.Http;
public static class StaticWebAppsAuth
{
private class ClientPrincipal
{
public string IdentityProvider { get; set; }
public string UserId { get; set; }
public string UserDetails { get; set; }
public IEnumerable<string> UserRoles { get; set; }
}
public static ClaimsPrincipal Parse(HttpRequest req)
{
var principal = new ClientPrincipal();
if (req.Headers.TryGetValue("x-ms-client-principal", out var header))
{
var data = header[0];
var decoded = Convert.FromBase64String(data);
var json = Encoding.UTF8.GetString(decoded);
principal = JsonSerializer.Deserialize<ClientPrincipal>(json, new JsonSerializerOptions { PropertyNameCaseInsensitive = true });
}
principal.UserRoles = principal.UserRoles?.Except(new string[] { "anonymous" }, StringComparer.CurrentCultureIgnoreCase);
if (!principal.UserRoles?.Any() ?? true)
{
return new ClaimsPrincipal();
}
var identity = new ClaimsIdentity(principal.IdentityProvider);
identity.AddClaim(new Claim(ClaimTypes.NameIdentifier, principal.UserId));
identity.AddClaim(new Claim(ClaimTypes.Name, principal.UserDetails));
identity.AddClaims(principal.UserRoles.Select(r => new Claim(ClaimTypes.Role, r)));
return new ClaimsPrincipal(identity);
}
}
When a user is logged in, the x-ms-client-principal
header is added to the requests for user information via the Static Web Apps edge nodes.
1 The fetch API and await operator aren't supported in Internet Explorer.
[!div class="nextstepaction"] Configure app settings