fix: JWT tokens expire instantly + double /api prefix in analytics
All checks were successful
Test Asgard Runner / test (push) Successful in 3s

- Auth service used flat env var names (JWT_SECRET, JWT_ACCESS_EXPIRY_SECONDS)
  but @nestjs/config nests them under jwt.* — configService.get() returned
  undefined, so expiresIn was 0 and tokens expired on issue (iat === exp)
- JWT strategy had same bug for secretOrKey
- AnalyticsView passed /api/analytics/... to useApi which already prepends /api,
  resulting in /api/api/analytics/... (404)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Vantz Stockwell
2026-02-15 21:40:32 -05:00
parent 2ad6a658ca
commit e849d7803c
3 changed files with 10 additions and 10 deletions

View File

@@ -146,7 +146,7 @@ export class AuthService {
async refresh(refreshToken: string) {
try {
const payload = await this.jwtService.verifyAsync(refreshToken, {
secret: this.configService.get<string>('JWT_SECRET'),
secret: this.configService.get<string>('jwt.secret'),
});
const user = await this.userRepository.findOne({
@@ -166,8 +166,8 @@ export class AuthService {
is_super_admin: user.is_super_admin,
},
{
secret: this.configService.get<string>('JWT_SECRET'),
expiresIn: this.configService.get<number>('JWT_ACCESS_EXPIRY_SECONDS', 3600),
secret: this.configService.get<string>('jwt.secret'),
expiresIn: this.configService.get<number>('jwt.accessExpirySeconds') || 900,
},
);
@@ -322,13 +322,13 @@ export class AuthService {
};
const accessToken = await this.jwtService.signAsync(payload, {
secret: this.configService.get<string>('JWT_SECRET'),
expiresIn: this.configService.get<number>('JWT_ACCESS_EXPIRY_SECONDS', 3600),
secret: this.configService.get<string>('jwt.secret'),
expiresIn: this.configService.get<number>('jwt.accessExpirySeconds') || 900,
});
const refreshToken = await this.jwtService.signAsync(payload, {
secret: this.configService.get<string>('JWT_SECRET'),
expiresIn: this.configService.get<number>('JWT_REFRESH_EXPIRY_SECONDS', 604800), // 7 days default
secret: this.configService.get<string>('jwt.secret'),
expiresIn: this.configService.get<number>('jwt.refreshExpirySeconds') || 604800,
});
return {

View File

@@ -34,7 +34,7 @@ export class JwtStrategy extends PassportStrategy(Strategy) {
super({
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
ignoreExpiration: false,
secretOrKey: configService.get<string>('JWT_SECRET'),
secretOrKey: configService.get<string>('jwt.secret'),
});
}

View File

@@ -33,8 +33,8 @@ const loadAnalytics = async () => {
const hours = rangeToHours(timeRange.value)
const [summaryRes, timeseriesRes] = await Promise.all([
api.get<AnalyticsSummary>(`/api/analytics/summary?range=${hours}`),
api.get<TimeseriesData>(`/api/analytics/timeseries?range=${hours}&granularity=hourly`)
api.get<AnalyticsSummary>(`/analytics/summary?range=${hours}`),
api.get<TimeseriesData>(`/analytics/timeseries?range=${hours}&granularity=hourly`)
])
summary.value = summaryRes