sourcefuse / sourcefuse/loopback4-microservice-catalog

authentication-service: lastLogin field not updated in JWT token on subsequent logins

Open
#2,402 1 comment 0 reactions 1 assignee View on GitHub

@piyushsinghgaur1 is already working on this.

Since Feb 9, 2026.

  • #2410 by @piyushsinghgaur1 — open
Dominant language
TypeScript
Stars
297
Forks
78
Avg merge
2d 3h
Merged PRs (30d)
4

Description

Describe the bug
The lastLogin field in the JWT token is not being updated on subsequent logins. When a user logs in, the token contains the stale/old lastLogin timestamp instead of the current login time.

To Reproduce
Steps to reproduce the behavior:

  1. Login as a user (not first-time login) via /auth/login endpoint
  2. Exchange the auth code for a token via /auth/token endpoint
  3. Decode the resulting accessToken JWT
  4. Check the lastLogin claim in the payload
  5. The lastLogin value will be from the previous login, not the current one

Expected behavior
The lastLogin field in the JWT token should reflect the current login timestamp after each successful login.

Root Cause
In src/services/idp-login.service.ts, the generateToken method has this logic (lines 154-161):

if (
payload.userId &&
!(await this.userRepo.firstTimeUser(payload.userId))
) {
await this.userRepo.updateLastLogin(payload.userId);
}

return await this.createJWT(payload, authClient, LoginType.ACCESS);

The issue is twofold:

  1. Wrong condition check: The code checks payload.userId, but after login the user data is in payload.user (not payload.userId). The condition fails because payload.userId is undefined, so updateLastLogin() is never called.
  2. Stale user object: Even if updateLastLogin() were called, the createJWT method (line 208-209) uses the cached payload.user object:
    if (payload.user) {
    user = payload.user; // ← Uses OLD user object before DB update
    }
  3. This object still has the old lastLogin value since it's not refetched from the database after the update.

Suggested Fix
Update the generateToken method to:

  1. Check payload.user?.id instead of payload.userId
  2. Update the in-memory payload.user.lastLogin with the current timestamp after the DB update

if (
payload.user?.id &&
!(await this.userRepo.firstTimeUser(payload.user.id))
) {
await this.userRepo.updateLastLogin(payload.user.id);
payload.user.lastLogin = new Date(); // Update the in-memory object
}

return await this.createJWT(payload, authClient, LoginType.ACCESS);

Additional context

  • This affects all JWT-based authentication flows using the /auth/token endpoint
  • The lastLogin field is important for audit trails, session management, and security monitoring
  • Users relying on this field for displaying "last seen" information will see incorrect timestamps

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.