microsoft / ApplicationInsights-node.js

Microsoft Application Insights SDK for Node.js
MIT License
325 stars 139 forks source link

Support `setAuthenticatedUserContext` #356

Open gregberns opened 6 years ago

gregberns commented 6 years ago

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:

OsvaldoRosado commented 6 years ago

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.

glenjamin commented 6 years ago

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

OsvaldoRosado commented 6 years ago

There's a few workarounds for doing this per-request today (though perhaps faking the user cookie is actually easiest!):

glenjamin commented 6 years ago

Aha, telemetry processor looks like just the ticket.

Are there any pointers to docs on this other than in these issues?

glenjamin commented 6 years ago

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.

OsvaldoRosado commented 6 years ago

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.

glenjamin commented 6 years ago

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;
  }
}
goto1 commented 3 years ago

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!

imduchy commented 1 year ago

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;
  });
PieterWillemen commented 9 months ago

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;
  });

This does not set User Id for me. Only Auth Id.