Support `setAuthenticatedUserContext`
The ApplicationInsights-JS SDK supports a method called setAuthenticatedUserContext which sends a custom auth token with each event.
The client code is basically just doing some validation then updating the ai.user.authUserId tag.
On the server, it looks like the same thing can be done, but is not documented:
let client = appInsights.defaultClient;
let key = client.context.keys.userAuthUserId;
client.context.tags[key] = <authToken>;
Providing this same method on the server side would be helpful for several reasons:
- A users client and server activity can be tied together by the custom auth id
- SDK users don't have to figure this out themselves
- SDK consistency
Great catch!
The JS SDK can also provide this userId to the server-side using the "ai_authUser" cookie. It's my understanding that our .NET SDK will read this cookie and automatically set the authUserId that it received from the JS SDK. It would be nice to implement that here as well.
This would be really useful to be able to do on a per-request basis.
At the moment the only way I can see to add a username field on the server is to fake the user cookie
There's a few workarounds for doing this per-request today (though perhaps faking the user cookie is actually easiest!):
- If you're manually collecting requests, you can use the
tagOverridesparameter at track time - If you're automatically collecting requests, you can use
appInsights.getCorrelationContext()to set a field that you can access within the context object of a telemetry processor. The telemetry processor can then fill in this field on the envelope.- The upside to this approach vs any others is that you can get the user id set on the related telemetry as well (dependencies, exceptions, etc). This issue covers the approach in general: https://github.com/Microsoft/ApplicationInsights-node.js/issues/392
Aha, telemetry processor looks like just the ticket.
Are there any pointers to docs on this other than in these issues?
Oh right, I did see it in the README. Perhaps adding an example of logging auth would be good to add. I’ll have a poke around and maybe send in a PR.
Glad you found it! Adding an example to the README would definitely be a welcome addition.
For your own implementation, I would make sure to look at the discussion within #392 over the data privacy implications of getCorrelationContext().customProperties and the alternative presented if the implications are not desirable.
This is what I ended up going with
appInsights.defaultClient.addTelemetryProcessor(attachUserId);
function attachUserId(envelope, context) {
const res = context['http.ServerResponse'];
if (res && res.locals && res.locals.user) {
envelope.tags['ai.user.authUserId'] = res.locals.user.username;
}
}
Is using context['http.ServerResponse'] to grab per-request information a safe thing to do here or should I use the getCorrelationContext().customProperties to temporarily save some information that will help me determine whether I should create a log for this request or not?
appInsights.defaultClient.addTelemetryProcessor(
(envelope, context) => {
const originalUrl = context["http.ServerRequest"]?.originalUrl;
if (originalUrl === "/some-route-i-dont-care-about") return false;
}
)
Or should I do the following?
appInsights.defaultClient.addTelemetryProcessor(
(envelope, context) => {
const requestContext = appInsights.getCorrelationContext().customProperties;
if (requestContext.originalUrl === "/some-route-i-dont-care-about") return false;
}
)
Any tips would be greatly appreciated here, thanks!
I ended up doing this to add a username to a request's properties. I'm also curious if it's better to use customProperties with an express middleware where I'd populate username to customProperties, rather than this approach.
appInsights.defaultClient.addTelemetryProcessor((envelope, context) => {
if (context) {
const req = context['http.ServerRequest'];
if (req && req.user) {
envelope.tags['ai.user.authUserId'] = req.user.username;
envelope.tags['ai.user.userId'] = req.user._id;
}
}
return true;
});
I ended up doing this to add a username to a request's properties. I'm also curious if it's better to use
customPropertieswith an express middleware where I'd populateusernametocustomProperties, rather than this approach.appInsights.defaultClient.addTelemetryProcessor((envelope, context) => { if (context) { const req = context['http.ServerRequest']; if (req && req.user) { envelope.tags['ai.user.authUserId'] = req.user.username; envelope.tags['ai.user.userId'] = req.user._id; } } return true; });
This does not set User Id for me. Only Auth Id.