auth modified for sliding time

This commit is contained in:
Kallesh B S 2025-06-19 16:59:03 +05:30
parent 8b964d2c84
commit 7770642b80
4 changed files with 106 additions and 36 deletions

View File

@ -26,7 +26,7 @@ export class AuthController {
httpOnly: true, httpOnly: true,
secure: true, // set to true if you're on HTTPS secure: true, // set to true if you're on HTTPS
sameSite: 'none', // adjust based on your needs (strict, lax , none) sameSite: 'none', // adjust based on your needs (strict, lax , none)
maxAge: 90 * 1000, // convert seconds to ms if applicable maxAge: 8 * 60 * 60 * 1000, // convert seconds to ms if applicable
}); });
} }
@ -35,7 +35,7 @@ export class AuthController {
httpOnly: true, httpOnly: true,
secure: true, // set to true if you're on HTTPS secure: true, // set to true if you're on HTTPS
sameSite: 'none', // adjust based on your needs (strict, lax , none) sameSite: 'none', // adjust based on your needs (strict, lax , none)
maxAge: 90 * 1000, // convert seconds to ms if applicable maxAge: 8 * 60 * 60 * 1000, // convert seconds to ms if applicable
}); });
} }
@ -75,7 +75,7 @@ export class AuthController {
httpOnly: true, httpOnly: true,
secure: true, // set to true if you're on HTTPS secure: true, // set to true if you're on HTTPS
sameSite: 'none', // adjust based on your needs (strict, lax , none) sameSite: 'none', // adjust based on your needs (strict, lax , none)
maxAge: 90 * 1000, // convert seconds to ms if applicable maxAge: 8 * 60 * 60 * 1000, // convert seconds to ms if applicable
path: '/' path: '/'
}); });
} }
@ -85,7 +85,7 @@ export class AuthController {
httpOnly: true, httpOnly: true,
secure: true, // set to true if you're on HTTPS secure: true, // set to true if you're on HTTPS
sameSite: 'none', // adjust based on your needs (strict, lax , none) sameSite: 'none', // adjust based on your needs (strict, lax , none)
maxAge: 90 * 1000, // convert seconds to ms if applicable maxAge: 8 * 60 * 60 * 1000, // convert seconds to ms if applicable
path: '/' path: '/'
}); });
} }

View File

@ -53,7 +53,7 @@ export class AuthService {
this.TOKEN_URL = `${this.KEYCLOAK_BASE_URL}/token` this.TOKEN_URL = `${this.KEYCLOAK_BASE_URL}/token`
this.USERS_URL = `${this.KEYCLOAK_URL}/realms/${this.KEYCLOAK_REALM}/users`; this.USERS_URL = `${this.KEYCLOAK_URL}/admin/realms/${this.KEYCLOAK_REALM}/users`;
} }
async login(body: AuthLoginDTO) { async login(body: AuthLoginDTO) {
@ -132,37 +132,79 @@ export class AuthService {
async introspectToken(token: string): Promise<any> { async introspectToken(token: string): Promise<any> {
const params = new URLSearchParams(); console.log("from AuthService introspectToken .......................... end");
params.append('token', token);
params.append('client_id', this.CLIENT_ID);
params.append('client_secret', this.CLIENT_SECRET);
let det: any = await jwt.decode(token);
const response = await axios.post(this.TOKENS_INTROSPECT_URL, params, { const { email } = det;
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
console.log("email : ", email);
let uid = await this.getUserIdByEmail(email);
console.log("uid : ", uid);
const USERINFO_URL = `${this.KEYCLOAK_URL}/admin/realms/${this.KEYCLOAK_REALM}/users/${uid}/sessions`;
const admintoken = await this.getAdminAccessToken();
try {
console.log("url : ", USERINFO_URL);
const response = await axios.get(USERINFO_URL, {
headers: {
Authorization: `Bearer ${admintoken}`
}
}); });
return response.data; console.log("active session data : ", response.data);
console.log("from AuthService decodeToken .......................... end");
if (response.data.length > 0) return { active: true };
else return { active: false }
} catch (error) {
console.log("Error in introspectToken : ", error.message);
throw new InternalServerErrorException()
}
} }
async decodeToken(token: string): Promise<any> { async decodeToken(token: string): Promise<any> {
console.log("from AuthService decodeToken .......................... start");
const decodedHeader = jwt.decode(token, { complete: true }); const decodedHeader = jwt.decode(token, { complete: true });
if (!decodedHeader || typeof decodedHeader !== 'object') { if (!decodedHeader || typeof decodedHeader !== 'object') {
throw new Error('Invalid token format'); throw new Error('Invalid token format');
} }
console.log("✅ token decoded from decodeToken");
const kid: any = decodedHeader.header.kid; const kid: any = decodedHeader.header.kid;
const publicKey = await this.getPublicKey(kid); const publicKey = await this.getPublicKey(kid);
console.log("✅ publicKey got from decodeToken");
const introspection = await this.introspectToken(token); const introspection = await this.introspectToken(token);
console.log("introspection : ", introspection.active, " : so Unauthorized!"); console.log("✅ introspection got from decodeToken");
if (!introspection.active) { if (!introspection.active) {
throw new Error('Unauthorized'); console.log("❌ introspection active from decodeToken");
console.log("from AuthService decodeToken .......................... end");
throw new UnauthorizedException("Authentication Failed")
} }
console.log("✅ introspection active from decodeToken");
const verified = jwt.verify(token, publicKey, { algorithms: ['RS256'] }); const verified = jwt.verify(token, publicKey, { algorithms: ['RS256'] });
console.log("✅ token verification successufull from decodeToken");
console.log("from AuthService decodeToken .......................... end");
return verified; return verified;
} }
@ -197,6 +239,7 @@ export class AuthService {
params.append('client_secret', this.CLIENT_SECRET); params.append('client_secret', this.CLIENT_SECRET);
params.append('username', username); params.append('username', username);
params.append('password', password); params.append('password', password);
// params.append('scope', 'openid');
try { try {
const response = await axios.post(this.TOKEN_URL, params, { const response = await axios.post(this.TOKEN_URL, params, {
@ -225,6 +268,9 @@ export class AuthService {
let adminAccessToken = await this.getAdminAccessToken(); let adminAccessToken = await this.getAdminAccessToken();
console.log("admin access_token for getting uid : ", adminAccessToken);
console.log("url for uid : ", url);
const options: AxiosRequestConfig = { const options: AxiosRequestConfig = {
method: 'GET', method: 'GET',
url, url,
@ -239,7 +285,7 @@ export class AuthService {
return data[0]?.id; return data[0]?.id;
} catch (error) { } catch (error) {
// console.error(error); // console.error(error);
console.log(error.message); console.log("from getUserIdByEmail : ", error.message);
} }
} }
@ -305,7 +351,7 @@ export class AuthService {
{ {
headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
}); });
console.log(adminTokenResponse.data); // console.log(adminTokenResponse.data);
const adminAccessToken = adminTokenResponse.data.access_token; const adminAccessToken = adminTokenResponse.data.access_token;
@ -489,18 +535,28 @@ export class AuthService {
} }
async getTokenFromRefreshToken(req: Request) { async getTokenFromRefreshToken(req: Request) {
const refreshToken = req.cookies['refresh_token']; const refreshToken = req.cookies['refresh_token'];
if (!refreshToken) { if (!refreshToken) {
console.log("refesh token not present");
throw new UnauthorizedException('Authentication failed'); throw new UnauthorizedException('Authentication failed');
} }
console.log("refesh token present : ", refreshToken);
const params = new URLSearchParams(); const params = new URLSearchParams();
params.append('grant_type', 'refresh_token'); params.append('grant_type', 'refresh_token');
params.append('client_id', this.CLIENT_ID); params.append('client_id', this.CLIENT_ID);
params.append('client_secret', this.CLIENT_SECRET); params.append('client_secret', this.CLIENT_SECRET);
params.append('refresh_token', refreshToken); params.append('refresh_token', refreshToken);
console.log("url for refresh is : ", `${this.KEYCLOAK_URL}/auth/realms/${this.KEYCLOAK_REALM}/protocol/openid-connect/token`);
try { try {
const response = await axios.post(this.TOKEN_URL, params, { const response = await axios.post(this.TOKEN_URL, params, {
headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
@ -508,7 +564,15 @@ export class AuthService {
return response.data; return response.data;
} catch (error) { } catch (error) {
console.log(error.message); if (axios.isAxiosError(error) && error.response) {
console.error('🔴 Axios error:', {
status: error.response.status,
data: error.response.data,
});
} else {
console.error('🔴 Unexpected error:', error.message);
}
console.log("Error while refreshing tokens : ", error.message);
throw new UnauthorizedException('Authentication failed'); throw new UnauthorizedException('Authentication failed');
} }
} }

View File

@ -6,41 +6,44 @@ import {
Global, Global,
} from '@nestjs/common'; } from '@nestjs/common';
import { AuthService } from 'src/auth/auth.service'; import { AuthService } from 'src/auth/auth.service';
import * as jwt from 'jsonwebtoken';
import { InternalServerException } from 'src/exceptions/internalServerError.exception';
import { UnauthorizedException as UE} from 'src/exceptions/unauthorized.exception';
@Global() @Global()
@Injectable() @Injectable()
export class JwtAuthGuard implements CanActivate { export class JwtAuthGuard implements CanActivate {
constructor(private readonly authService: AuthService) {} constructor(private readonly authService: AuthService) { }
async canActivate(context: ExecutionContext): Promise<boolean> { async canActivate(context: ExecutionContext): Promise<boolean> {
const request = context.switchToHttp().getRequest(); const request = context.switchToHttp().getRequest();
// Read token from cookie
console.log('------------------------------');
let g = await request.cookies
console.log("g : ",g);
console.log(' guard cookies ------------------------------');
const token = request.cookies?.access_token; const token = request.cookies?.access_token;
if (!token) { if (!token) {
console.log('error from inspect token .....'); console.log('❌ No access token found');
throw new UnauthorizedException('Authentication failed'); throw new UnauthorizedException('Authentication failed');
} }
console.log("✅ access_token is present in JwtAuthGuard");
try { try {
const decoded = await this.authService.decodeToken(token); const decoded = await this.authService.decodeToken(token);
request.user = decoded; request.user = decoded;
return true; return true;
} catch (err) { } catch (error) {
console.log("error in jwt-auth guard below decode : ",err.message); if (
error instanceof jwt.TokenExpiredError ||
error instanceof jwt.JsonWebTokenError
) {
console.log('❌ Token is invalid or expired');
throw new UnauthorizedException('Invalid Token');
}
else if (error instanceof UnauthorizedException || error instanceof UE) {
throw error;
}
console.log(error instanceof UE);
throw new UnauthorizedException({ throw new InternalServerException();
message: 'Invalid Token',
error: 'Unauthorized',
statusCode: 401,
});
} }
} }
} }

View File

@ -20,6 +20,9 @@ export class LogoutInterceptor implements NestInterceptor {
response.clearCookie('access_token'); response.clearCookie('access_token');
response.clearCookie('refresh_token'); response.clearCookie('refresh_token');
console.log("No tokens found so logging-out");
response.status(200).json({ response.status(200).json({
statusCode: 200, statusCode: 200,
message: 'Logged-Out successfully', message: 'Logged-Out successfully',