Description
Is there an existing issue for this?
- I have checked for existing issues https://github.com/getsentry/sentry-javascript/issues
- I have reviewed the documentation https://docs.sentry.io/
- I am using the latest SDK release https://github.com/getsentry/sentry-javascript/releases
How do you use Sentry?
Sentry Saas (sentry.io)
Which SDK are you using?
@sentry/node
SDK Version
8.20.0
Framework Version
@sentry/node
Link to Sentry event
No response
Reproduction Example/SDK Setup
How to set User per request in Node?
From Scopes Documentation:
For instance, a web server might handle multiple requests at the same time, and each request may have different scope data to apply to its events.
The isolation scope is used to isolate events from each other. For example, each request in a web server might get its own isolation scope, so that events from one request don't interfere with events from another request. In most cases, you'll want to put data that should be applied to your events on the isolation scope - which is also why all Sentry.setXXX methods, like Sentry.setTag(), will write data onto the currently active isolation scope. A classic example for data that belongs on the isolation scope is a user - each request may have a different user, so you want to make sure that the user is set on the isolation scope
... The documentation matches exactly the behavior needed. However, it simply does not work.
- make an authenticated request, lookup user details, call
setUser
- make an unauthenticated request, do not call to
setUser
for this request (scope) because we don't have one, and throw an error manually
Problems
- The manually thrown error will report the User from the previous authenticated request.
- The same problem exists for spans.
- This is intentionally simple, but we've seen many errors report the wrong user
This example using Express should demonstrate...
import * as Sentry from '@sentry/node';
import bodyParser from 'body-parser';
import express, { Application, NextFunction, Request, Response, Router } from 'express';
Sentry.init({
dsn: undefined, // not needed for local debugging to reveal the issue
beforeSend: (event, hint, ...args) => {
const { type, contexts, exception, extra, tags, message, user, request } = event;
console.dir(
{
whoami: 'sentry:beforeSend',
event: { type, contexts, exception, extra, tags, message, user, request },
hint,
args
},
{ depth: null }
);
return event;
},
skipOpenTelemetrySetup: true
});
const app: Application = express();
const router = Router();
router.use(bodyParser.urlencoded({ extended: true, limit: '500kb' }));
router.use(bodyParser.json({ limit: '500kb' }));
const Users: { id: string; email: string; name: string }[] = [
{ id: '1', email: '[email protected]', name: 'foo example' },
{ id: '2', email: '[email protected]', name: 'foo example2' },
{ id: '3', email: '[email protected]', name: 'foo example3' },
{ id: '4', email: '[email protected]', name: 'foo example4' }
];
router.use('/users', function (req, res, next) {
try {
const authUser = Users.find((u) => u.id === req.headers['authorization']);
if (authUser) {
Sentry.setTag('Authenticated', true);
Sentry.setUser(authUser);
res.json(Users);
} else {
throw new Error('Authentication Error');
}
} catch (err) {
next(err);
}
});
app.use('/api', router);
app.use(function (err: Error, req: Request, res: Response, next: NextFunction) {
const { method, originalUrl, params, query, body } = req;
const { statusCode, locals } = res;
Sentry.withScope((scope) => {
scope.setExtras({
request: { method, originalUrl, params, query, body },
response: { statusCode, locals }
});
const eventId = Sentry.captureException(err);
(res as { sentry?: string }).sentry = eventId;
});
next(err);
});
// Or just use this, which is identical to above, without `extras`
// Sentry.setupExpressErrorHandler(app);
const PORT = process.env.PORT || 3000
app.listen(PORT, () => {
console.log(`API running @ http://localhost:${PORT}`);
});
Steps to Reproduce
Send the following requests:
# make an "authenticated" request
curl --header "authorization: 1" --header "content-type: application/json" http://localhost:3000/api/users
# subsequently make an unauthenticated request
curl --header "authorization: 798798798798" --header "content-type: application/json" http://localhost:3000/api/users
Expected Result
Logs show different user
context. Also, this is only a very simple issue. We've seen many user
s mis reported in our Prod environment. So it would seem that Scopes are not isolated to a request.
Actual Result
same user
for requests with different auth
Metadata
Metadata
Assignees
Type
Projects
Status