Note
Access to this page requires authorization. You can try signing in or changing directories.
Access to this page requires authorization. You can try changing directories.
Our extension provides two input binding targeting different needs.
-
To let a client connect to Azure Web PubSub Service, it must know the service endpoint URL and a valid access token. The
WebPubSubConnection
input binding produces required information, so client doesn't need to handle this token generation itself. The token is time-limited and can authenticate a specific user to a connection. Therefore, don't cache the token or share it between clients. An HTTP trigger working with this input binding can be used for clients to retrieve the connection information. -
When using is Static Web Apps,
HttpTrigger
is the only supported trigger and under Web PubSub scenario, we provide theWebPubSubContext
input binding helps users deserialize upstream http request from service side under Web PubSub protocols. So customers can get similar results comparing toWebPubSubTrigger
to easily handle in functions. When used withHttpTrigger
, customer requires to configure the HttpTrigger exposed url in event handler accordingly.
WebPubSubConnection
Example
The following example shows an HTTP trigger function that acquires Web PubSub connection information using the input binding and returns it over HTTP. In following example, the UserId
is passed in through client request query part like ?userid={User-A}
.
[Function("WebPubSubConnectionInputBinding")]
public static HttpResponseData Run([HttpTrigger(AuthorizationLevel.Anonymous)] HttpRequestData req,
[WebPubSubConnectionInput(Hub = "<hub>", , UserId = "{query.userid}", Connection = "<web_pubsub_connection_name>")] WebPubSubConnection connectionInfo)
{
var response = req.CreateResponse(HttpStatusCode.OK);
response.WriteAsJsonAsync(connectionInfo);
return response;
}
const { app, input } = require('@azure/functions');
const connection = input.generic({
type: 'webPubSubConnection',
name: 'connection',
userId: '{query.userId}',
hub: '<hub>'
});
app.http('negotiate', {
methods: ['GET', 'POST'],
authLevel: 'anonymous',
extraInputs: [connection],
handler: async (request, context) => {
return { body: JSON.stringify(context.extraInputs.get('connection')) };
},
});
Create a folder negotiate and update negotiate/function.json and copy following JSON codes.
{
"scriptFile": "__init__.py",
"bindings": [
{
"authLevel": "anonymous",
"type": "httpTrigger",
"direction": "in",
"name": "req"
},
{
"type": "http",
"direction": "out",
"name": "$return"
},
{
"type": "webPubSubConnection",
"name": "connection",
"userId": "{query.userid}",
"hub": "<hub>",
"direction": "in"
}
]
}
Define function in negotiate/init.py.
import logging
import azure.functions as func
def main(req: func.HttpRequest, connection) -> func.HttpResponse:
return func.HttpResponse(connection)
Note
Complete samples for this language are pending
Note
The Web PubSub extensions for Java isn't supported yet.
Get authenticated user ID
If the function is triggered by an authenticated client, you can add a user ID claim to the generated token. You can easily add authentication to a function app using App Service Authentication.
App Service Authentication sets HTTP headers named x-ms-client-principal-id
and x-ms-client-principal-name
that contain the authenticated user's client principal ID and name, respectively.
You can set the UserId
property of the binding to the value from either header using a binding expression: {headers.x-ms-client-principal-id}
or {headers.x-ms-client-principal-name}
.
[Function("WebPubSubConnectionInputBinding")]
public static HttpResponseData Run([HttpTrigger(AuthorizationLevel.Anonymous)] HttpRequestData req,
[WebPubSubConnectionInput(Hub = "<hub>", , UserId = "{headers.x-ms-client-principal-id}", Connection = "<web_pubsub_connection_name>")] WebPubSubConnection connectionInfo)
{
var response = req.CreateResponse(HttpStatusCode.OK);
response.WriteAsJsonAsync(connectionInfo);
return response;
}
const { app, input } = require('@azure/functions');
const connection = input.generic({
type: 'webPubSubConnection',
name: 'connection',
userId: '{headers.x-ms-client-principal-id}',
hub: '<hub>'
});
app.http('negotiate', {
methods: ['GET', 'POST'],
authLevel: 'anonymous',
extraInputs: [connection],
handler: async (request, context) => {
return { body: JSON.stringify(context.extraInputs.get('connection')) };
},
});
Create a folder negotiate and update negotiate/function.json and copy following JSON codes.
{
"scriptFile": "__init__.py",
"bindings": [
{
"authLevel": "anonymous",
"type": "httpTrigger",
"direction": "in",
"name": "req"
},
{
"type": "http",
"direction": "out",
"name": "$return"
},
{
"type": "webPubSubConnection",
"name": "connection",
"userId": "{headers.x-ms-client-principal-id}",
"hub": "<hub>",
"direction": "in"
}
]
}
Define function in negotiate/init.py.
import logging
import azure.functions as func
def main(req: func.HttpRequest, connection) -> func.HttpResponse:
return func.HttpResponse(connection)
Note
Complete samples for this language are pending
Note
The Web PubSub extensions for Java isn't supported yet.
Configuration
The following table explains the binding configuration properties that you set in the function.json file and the WebPubSubConnection
attribute.
function.json property | Attribute property | Description |
---|---|---|
type | n/a | Must be set to webPubSubConnection |
direction | n/a | Must be set to in |
name | n/a | Variable name used in function code for input connection binding object. |
hub | Hub | Required - The value must be set to the name of the Web PubSub hub for the function to be triggered. We support set the value in attribute as higher priority, or it can be set in app settings as a global value. |
userId | UserId | Optional - the value of the user identifier claim to be set in the access key token. |
clientProtocol | ClientProtocol | Optional - The client protocol type. Valid values include default and mqtt . For MQTT clients, you must set it to mqtt . For other clients, you can omit the property or set it to default . |
connection | Connection | Required - The name of the app setting that contains the Web PubSub Service connection string (defaults to "WebPubSubConnectionString"). |
Usage
WebPubSubConnection
provides following properties.
Binding Name | Binding Type | Description |
---|---|---|
BaseUri | Uri | Web PubSub client connection uri. |
Uri | Uri | Absolute Uri of the Web PubSub connection, contains AccessToken generated base on the request. |
AccessToken | string | Generated AccessToken based on request UserId and service information. |
WebPubSubConnection
provides following properties.
Binding Name | Description |
---|---|
baseUrl | Web PubSub client connection uri. |
url | Absolute Uri of the Web PubSub connection, contains AccessToken generated base on the request. |
accessToken | Generated AccessToken based on request UserId and service information. |
Note
The Web PubSub extensions for Java isn't supported yet.
More customization of generated token
Limited to the binding parameter types don't support a way to pass list nor array, the WebPubSubConnection
isn't fully supported with all the parameters server SDK has, especially roles
, and also includes groups
and expiresAfter
.
When customer needs to add roles or delay building the access token in the function, we suggest you to work with server SDK for C#.
[Function("WebPubSubConnectionCustomRoles")]
public static HttpResponseData Run([HttpTrigger(AuthorizationLevel.Anonymous)] HttpRequestData req)
{
var serviceClient = new WebPubSubServiceClient(new Uri(endpoint), "<hub>", "<web-pubsub-connection-string>");
var userId = req.Query["userid"].FirstOrDefault();
// your method to get custom roles.
var roles = GetRoles(userId);
var url = await serviceClient.GetClientAccessUriAsync(TimeSpan.FromMinutes(5), userId, roles);
var response = req.CreateResponse(HttpStatusCode.OK);
response.WriteString(url.ToString());
return response;
}
When customer needs to add roles or delay building the access token in the function, we suggest you working with server SDK for JavaScript.
const { app } = require('@azure/functions');
const { WebPubSubServiceClient } = require('@azure/web-pubsub');
app.http('negotiate', {
methods: ['GET', 'POST'],
authLevel: 'anonymous',
handler: async (request, context) => {
const serviceClient = new WebPubSubServiceClient(process.env.WebPubSubConnectionString, "<hub>");
let token = await serviceClient.getAuthenticationToken({ userId: req.query.userid, roles: ["webpubsub.joinLeaveGroup", "webpubsub.sendToGroup"] });
return { body: token.url };
},
});
Note
Complete samples for this language are pending
Note
The Web PubSub extensions for Java isn't supported yet.
WebPubSubContext
Example
// validate method when upstream set as http://<func-host>/api/{event}
[Function("validate")]
public static HttpResponseData Validate(
[HttpTrigger(AuthorizationLevel.Anonymous, "options")] HttpRequestData req,
[WebPubSubContextInput] WebPubSubContext wpsReq)
{
return BuildHttpResponseData(req, wpsReq.Response);
}
// Respond AbuseProtection to put header correctly.
private static HttpResponseData BuildHttpResponseData(HttpRequestData request, SimpleResponse wpsResponse)
{
var response = request.CreateResponse();
response.StatusCode = (HttpStatusCode)wpsResponse.Status;
response.Body = response.Body;
foreach (var header in wpsResponse.Headers)
{
response.Headers.Add(header.Key, header.Value);
}
return response;
}
const { app, input } = require('@azure/functions');
const wpsContext = input.generic({
type: 'webPubSubContext',
name: 'wpsContext'
});
app.http('connect', {
methods: ['GET', 'POST'],
authLevel: 'anonymous',
extraInputs: [wpsContext],
handler: async (request, context) => {
var wpsRequest = context.extraInputs.get('wpsContext');
return { "userId": wpsRequest.request.connectionContext.userId };
}
});
Note
Complete samples for this language are pending
Note
The Web PubSub extensions for Java isn't supported yet.
Configuration
The following table explains the binding configuration properties that you set in the functions.json file and the WebPubSubContext
attribute.
function.json property | Attribute property | Description |
---|---|---|
type | n/a | Must be set to webPubSubContext . |
direction | n/a | Must be set to in . |
name | n/a | Variable name used in function code for input Web PubSub request. |
connection | Connection | Optional - the name of an app settings or setting collection that specifies the upstream Azure Web PubSub service. The value is used for Abuse Protection and Signature validation. The value is auto resolved with "WebPubSubConnectionString" by default. And null means the validation isn't needed and always succeed. |
Important
For optimal security, your function app should use managed identities when connecting to the Web PubSub service instead of using a connection string, which contains a shared secret key. For more information, see Authorize a managed identity request by using Microsoft Entra ID.
Usage
WebPubSubContext
provides following properties.
Binding Name | Binding Type | Description | Properties |
---|---|---|---|
request | WebPubSubEventRequest |
Request from client, see following table for details. | WebPubSubConnectionContext from request header and other properties deserialized from request body describe the request, for example, Reason for DisconnectedEventRequest . |
response | HttpResponseMessage |
Extension builds response mainly for AbuseProtection and errors cases. |
- |
errorMessage | string | Describe the error details when processing the upstream request. | - |
hasError | bool | Flag to indicate whether it's a valid Web PubSub upstream request. | - |
isPreflight | bool | Flag to indicate whether it's a preflight request of AbuseProtection . |
- |
For WebPubSubEventRequest
, it's deserialized to different classes that provide different information about the request scenario. For PreflightRequest
or not valid cases, user can check the flags IsPreflight
and HasError
to know. We suggest you to return system build response WebPubSubContext.Response
directly, or customer can log errors on demand. In different scenarios, customer can read the request properties as following.
Derived Class | Description | Properties |
---|---|---|
PreflightRequest |
Used in AbuseProtection when IsPreflight is true |
- |
ConnectEventRequest |
Used in system Connect event type |
Claims, Query, Subprotocols, ClientCertificates |
ConnectedEventRequest |
Used in system Connected event type |
- |
UserEventRequest |
Used in user event type | Data, DataType |
DisconnectedEventRequest |
Used in system Disconnected event type |
Reason |
Note
Though the WebPubSubContext
is an input binding provides similar request deserialize way under HttpTrigger
comparing to WebPubSubTrigger
, there's limitations, i.e. connection state post merge isn't supported. The return response is still respected by the service side, but users require to build the response themselves. If users have needs to set the event response, you should return a HttpResponseMessage
contains ConnectEventResponse
or messages for user event as response body and put connection state with key ce-connectionstate
in response header.