fix(auth): one-time SSO and MFA tokens, permission changes effective on every replica
- Every JWT carries a jti. The SSO completion token and the MFA challenge (once a code was accepted) are recorded as used in ConsumedToken; a replayed request or copied cookie cannot open a second session. Used ids are cleaned up after they expire. - The token-validity check (active user, active role, password change) reads fresh on every request and refreshes the permission cache, so a deactivation or role change made on another replica applies to the very next request instead of up to 30 s later. Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
This commit is contained in:
1 parent
fc6af8737b
commit
45efb08369
16 files changed
+166
-23
No files matched your search
@@ -165,15 +165,34 @@ describe('PermissionResolverService', () => {
|
||||
);
|
||||
});
|
||||
|
||||
it('shares the cached entry with getPermissions instead of re-querying', async () => {
|
||||
it('reads fresh every time and refreshes the cache for getPermissions', async () => {
|
||||
prisma.user.findUnique.mockResolvedValue(
|
||||
activeUserWithPermissions('colonies:read'),
|
||||
);
|
||||
|
||||
await resolver.getPermissions('user-1');
|
||||
await resolver.isTokenValid('user-1', nowSeconds);
|
||||
await resolver.getPermissions('user-1');
|
||||
|
||||
expect(prisma.user.findUnique).toHaveBeenCalledTimes(1);
|
||||
// One read for the first getPermissions, one fresh read for the
|
||||
// validity check - the second getPermissions uses that fresh entry.
|
||||
expect(prisma.user.findUnique).toHaveBeenCalledTimes(2);
|
||||
});
|
||||
|
||||
it('sees a deactivation made elsewhere on the next request', async () => {
|
||||
prisma.user.findUnique.mockResolvedValueOnce(
|
||||
activeUserWithPermissions('colonies:read'),
|
||||
);
|
||||
await expect(resolver.isTokenValid('user-1', nowSeconds)).resolves.toBe(
|
||||
true,
|
||||
);
|
||||
prisma.user.findUnique.mockResolvedValueOnce({
|
||||
...activeUserWithPermissions('colonies:read'),
|
||||
isActive: false,
|
||||
});
|
||||
await expect(resolver.isTokenValid('user-1', nowSeconds)).resolves.toBe(
|
||||
false,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
Reference in new issue
Block a user