Skip to content

Conversation

@piyushsinghgaur1
Copy link
Collaborator

@piyushsinghgaur1 piyushsinghgaur1 commented Feb 9, 2026

user lastLogin detail will be a part of the response body

#2402
GH-2402

This pull request updates the process for recording and handling the user's last login time across the authentication service. The changes ensure that a consistent timestamp is used when updating the user's last login and that this timestamp is also set in the returned in response body .

Last Login will not be a part of the token instead it will be a part of the response body.

…gin time

ensure JWT lastLogin reflects current login time

GH-2402
@piyushsinghgaur1 piyushsinghgaur1 self-assigned this Feb 9, 2026
Copilot AI review requested due to automatic review settings February 9, 2026 10:23
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Updates last-login tracking so the database update and JWT/user payload share the same captured timestamp for a login event.

Changes:

  • Add optional time parameter to UserRepository.updateLastLogin to support caller-provided timestamps.
  • Capture Date.now() once per login flow and reuse it for both persistence and response payload population.
  • Set payload.user.lastLogin during login flows to align with the recorded timestamp.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 4 comments.

File Description
services/authentication-service/src/services/idp-login.service.ts Capture a single login timestamp, persist it, and set it on the returned payload user.
services/authentication-service/src/repositories/user.repository.ts Allow updateLastLogin to accept a caller-provided timestamp (defaults to now).
services/authentication-service/src/modules/auth/controllers/login.controller.ts Mirror the IDP login flow change: single captured timestamp used for DB + payload.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

await this.userRepo.updateLastLogin(payload.user.id);
const time = Date.now();
await this.userRepo.updateLastLogin(payload.user.id, time);
payload.user.lastLogin = new Date(time);
Copy link

Copilot AI Feb 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

updateLastLogin persists a numeric timestamp (ms since epoch), but the payload sets lastLogin to a Date object. When serialized into JWT/JSON this typically becomes an ISO string, which may diverge from existing clients expecting a number. Consider keeping payload.user.lastLogin the same type as what the API/JWT historically exposed (e.g., set it to time if consumers expect a number) or update the repository/model to store a Date consistently end-to-end.

Suggested change
payload.user.lastLogin = new Date(time);
payload.user.lastLogin = time;

Copilot uses AI. Check for mistakes.
await this.userRepo.updateLastLogin(payload.user.id);
const time = Date.now();
await this.userRepo.updateLastLogin(payload.user.id, time);
payload.user.lastLogin = new Date(time);
Copy link

Copilot AI Feb 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same issue as in IdpLoginService: the DB update uses a millisecond timestamp while the payload assigns a Date. Align the payload lastLogin type with what downstream consumers expect (number vs Date/ISO string) to avoid subtle client/JWT compatibility breaks.

Suggested change
payload.user.lastLogin = new Date(time);
(payload.user as AnyObject).lastLogin = time;

Copilot uses AI. Check for mistakes.
}

async updateLastLogin(userId: string): Promise<void> {
async updateLastLogin(userId: string, time?: number): Promise<void> {
Copy link

Copilot AI Feb 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The new parameter name time is ambiguous (units and meaning). Consider renaming to something explicit like timeMs / timestampMs (or switching the parameter type to Date and naming it lastLoginAt) to reduce confusion and prevent accidental misuse.

Copilot uses AI. Check for mistakes.
userId,
{
lastLogin: Date.now(),
lastLogin: time ?? Date.now(),
Copy link

Copilot AI Feb 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The new parameter name time is ambiguous (units and meaning). Consider renaming to something explicit like timeMs / timestampMs (or switching the parameter type to Date and naming it lastLoginAt) to reduce confusion and prevent accidental misuse.

Copilot uses AI. Check for mistakes.
}

async updateLastLogin(userId: string): Promise<void> {
async updateLastLogin(userId: string, time?: number): Promise<void> {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I disagree to this approach. We should not send the timestamp here. it should always remain Date.now. The issue is this timestamp is not provided into JWT correctly. We should only fix that.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is for consistency that we store the "exact" same timestamp in the database and in the JWT token.

The issue is that if we do Date.now() inside this method and then again after or before calling this method, then the lastLogin field might be off by a few milliseconds.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I never said to do that twice

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now returning lastLogin as a part of the responseBody

) {
await this.userRepo.updateLastLogin(payload.user.id);
const time = Date.now();
await this.userRepo.updateLastLogin(payload.user.id, time);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use the returned lastlogin timestamp from the method and update it into payload.

userId,
{
lastLogin: Date.now(),
lastLogin: time ?? Date.now(),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

return the new lastlogin time from this function

userId,
{
lastLogin: Date.now(),
lastLogin: time ?? Date.now(),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

return the new lastlogin time from this function

}

async updateLastLogin(userId: string): Promise<void> {
async updateLastLogin(userId: string, time?: number): Promise<void> {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I never said to do that twice

@sonarqubecloud
Copy link

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

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

5 participants