Compare commits
2 Commits
8b964d2c84
...
600a1f7d75
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
600a1f7d75 | ||
|
|
7770642b80 |
@ -10,12 +10,6 @@ import { LogoutInterceptor } from 'src/interceptors/logout.interceptor';
|
|||||||
export class AuthController {
|
export class AuthController {
|
||||||
constructor(private readonly authService: AuthService) { }
|
constructor(private readonly authService: AuthService) { }
|
||||||
|
|
||||||
|
|
||||||
// @Post('/login')
|
|
||||||
// login(@Body() body: AuthLoginDTO) {
|
|
||||||
// return this.authService.login(body);
|
|
||||||
// }
|
|
||||||
|
|
||||||
@Post('login')
|
@Post('login')
|
||||||
@HttpCode(200)
|
@HttpCode(200)
|
||||||
async loginClient(@Body() body: AuthLoginDTO, @Res({ passthrough: true }) res: Response, @Req() req: Request) {
|
async loginClient(@Body() body: AuthLoginDTO, @Res({ passthrough: true }) res: Response, @Req() req: Request) {
|
||||||
@ -26,7 +20,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 +29,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 +69,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 +79,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: '/'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@ -11,6 +11,15 @@ import { UnauthorizedException } from 'src/exceptions/unauthorized.exception';
|
|||||||
import { ConflictException } from 'src/exceptions/conflict.exception';
|
import { ConflictException } from 'src/exceptions/conflict.exception';
|
||||||
import { BadRequestException } from 'src/exceptions/badRequest.exception';
|
import { BadRequestException } from 'src/exceptions/badRequest.exception';
|
||||||
|
|
||||||
|
interface DecodedToken {
|
||||||
|
email: string;
|
||||||
|
[key: string]: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IntrospectResult {
|
||||||
|
active: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class AuthService {
|
export class AuthService {
|
||||||
private keyCache: Record<string, string> = {};
|
private keyCache: Record<string, string> = {};
|
||||||
@ -53,7 +62,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) {
|
||||||
@ -121,75 +130,172 @@ export class AuthService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private async getPublicKey(kid: string): Promise<string> {
|
private async getPublicKey(kid: string): Promise<string> {
|
||||||
if (this.keyCache[kid]) return this.keyCache[kid];
|
try {
|
||||||
const { data } = await axios.get(this.JWKS_URL);
|
// Check if the key is already cached
|
||||||
const key = data.keys.find((k) => k.kid === kid);
|
if (this.keyCache[kid]) return this.keyCache[kid];
|
||||||
if (!key) throw new InternalServerErrorException('Key not found');
|
|
||||||
const pem = jwkToPem(key);
|
// Fetch the JWKS (JSON Web Key Set)
|
||||||
this.keyCache[kid] = pem;
|
const { data } = await axios.get(this.JWKS_URL);
|
||||||
return pem;
|
|
||||||
|
// Validate the response shape
|
||||||
|
if (!data?.keys || !Array.isArray(data.keys)) {
|
||||||
|
console.log("Invalid JWKS response");
|
||||||
|
throw new UnauthorizedException('Authentication failed');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find the key with the matching kid
|
||||||
|
const key = data.keys.find((k) => k.kid === kid);
|
||||||
|
if (!key) {
|
||||||
|
console.log("Authentication failed: Key not found");
|
||||||
|
throw new UnauthorizedException('Authentication failed');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert JWK to PEM format and cache it
|
||||||
|
const pem = jwkToPem(key);
|
||||||
|
this.keyCache[kid] = pem;
|
||||||
|
|
||||||
|
return pem;
|
||||||
|
} catch (error) {
|
||||||
|
if (error instanceof UnauthorizedException) {
|
||||||
|
throw error; // Let UnauthorizedException bubble up as-is
|
||||||
|
}
|
||||||
|
// Optionally log error details for debugging
|
||||||
|
console.error('Failed to retrieve or process JWKS:', error);
|
||||||
|
// Wrap other errors as InternalServerException
|
||||||
|
console.log('Failed to retrieve public key');
|
||||||
|
throw new InternalServerErrorException();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async introspectToken(token: string): Promise<any> {
|
async introspectTokenX(token: string): Promise<any> {
|
||||||
|
let det: any = await jwt.decode(token);
|
||||||
|
|
||||||
const params = new URLSearchParams();
|
const { email } = det;
|
||||||
params.append('token', token);
|
|
||||||
params.append('client_id', this.CLIENT_ID);
|
|
||||||
params.append('client_secret', this.CLIENT_SECRET);
|
|
||||||
|
|
||||||
|
console.log("email : ", email);
|
||||||
|
|
||||||
const response = await axios.post(this.TOKENS_INTROSPECT_URL, params, {
|
let uid = await this.getUserIdByEmail(email);
|
||||||
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
|
||||||
});
|
|
||||||
|
|
||||||
return response.data;
|
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}`
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
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 introspectToken(token: string, publicKey: string): Promise<IntrospectResult> {
|
||||||
|
try {
|
||||||
|
// Securely verify the token
|
||||||
|
const decoded = jwt.verify(token, publicKey, { algorithms: ['RS256'], }) as DecodedToken;
|
||||||
|
|
||||||
|
const { email } = decoded;
|
||||||
|
|
||||||
|
if (!email) throw new UnauthorizedException('Token does not contain an email.');
|
||||||
|
|
||||||
|
// const uid = await this.getUserIdByEmail(email);
|
||||||
|
|
||||||
|
// if (!uid) throw new UnauthorizedException('No user ID found for email.');
|
||||||
|
|
||||||
|
// const userInfoUrl = `${this.KEYCLOAK_URL}/admin/realms/${this.KEYCLOAK_REALM}/users/${uid}/sessions`;
|
||||||
|
|
||||||
|
// const adminToken = await this.getAdminAccessToken();
|
||||||
|
|
||||||
|
// const response = await axios.get(userInfoUrl, {
|
||||||
|
// headers: {
|
||||||
|
// Authorization: `Bearer ${adminToken}`,
|
||||||
|
// },
|
||||||
|
// });
|
||||||
|
|
||||||
|
const sessionData = await this.getUserSession(email);
|
||||||
|
|
||||||
|
return { active: Array.isArray(sessionData) && sessionData.length > 0 };
|
||||||
|
|
||||||
|
} catch (error: any) {
|
||||||
|
console.log("Error in introspectToken:", error.message || error);
|
||||||
|
|
||||||
|
if (error instanceof UnauthorizedException || error instanceof jwt.TokenExpiredError || error instanceof jwt.JsonWebTokenError || error instanceof jwt.NotBeforeError) {
|
||||||
|
throw new UnauthorizedException('Authentication failed');
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new InternalServerErrorException('Failed to introspect token');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async getUserSession(email) {
|
||||||
|
try {
|
||||||
|
const uid = await this.getUserIdByEmail(email);
|
||||||
|
|
||||||
|
if (!uid) throw new UnauthorizedException('No user ID found for email.');
|
||||||
|
|
||||||
|
const userInfoUrl = `${this.KEYCLOAK_URL}/admin/realms/${this.KEYCLOAK_REALM}/users/${uid}/sessions`;
|
||||||
|
|
||||||
|
const adminToken = await this.getAdminAccessToken();
|
||||||
|
|
||||||
|
const response = await axios.get(userInfoUrl, {
|
||||||
|
headers: {
|
||||||
|
Authorization: `Bearer ${adminToken}`,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const sessionData = response.data;
|
||||||
|
|
||||||
|
return sessionData
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
if (error instanceof UnauthorizedException) throw error
|
||||||
|
console.log("Error while getting User session.....");
|
||||||
|
throw new InternalServerErrorException()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async decodeToken(token: string): Promise<any> {
|
async decodeToken(token: string): Promise<any> {
|
||||||
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 UnauthorizedException("Authentication failed")
|
||||||
}
|
}
|
||||||
|
|
||||||
const kid: any = decodedHeader.header.kid;
|
const kid: any = decodedHeader.header.kid;
|
||||||
|
|
||||||
const publicKey = await this.getPublicKey(kid);
|
const publicKey = await this.getPublicKey(kid);
|
||||||
|
|
||||||
const introspection = await this.introspectToken(token);
|
const introspection = await this.introspectToken(token, publicKey);
|
||||||
|
|
||||||
console.log("introspection : ", introspection.active, " : so Unauthorized!");
|
|
||||||
|
|
||||||
if (!introspection.active) {
|
if (!introspection.active) {
|
||||||
throw new Error('Unauthorized');
|
console.log("Introspect failed for token");
|
||||||
|
throw new UnauthorizedException("Authentication Failed")
|
||||||
}
|
}
|
||||||
|
|
||||||
const verified = jwt.verify(token, publicKey, { algorithms: ['RS256'] });
|
const verified = jwt.verify(token, publicKey, { algorithms: ['RS256'] });
|
||||||
return verified;
|
|
||||||
}
|
|
||||||
|
|
||||||
async getAdminAccessTokenx(): Promise<string> {
|
return verified;
|
||||||
const data = new URLSearchParams();
|
|
||||||
data.append('grant_type', 'client_credentials');
|
|
||||||
data.append('client_id', this.CLIENT_ID);
|
|
||||||
data.append('client_secret', this.CLIENT_SECRET);
|
|
||||||
try {
|
|
||||||
const response: AxiosResponse = await axios.post(this.KEYCLOAK_URL, data, {
|
|
||||||
headers: {
|
|
||||||
'Content-Type': 'application/x-www-form-urlencoded',
|
|
||||||
},
|
|
||||||
});
|
|
||||||
return response.data.access_token;
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Error getting Keycloak access token:', error.response ? error.response.data : error.message);
|
|
||||||
throw new Error('Failed to obtain Keycloak access token');
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async loginUser(username: string, password: string, req: Request): Promise<any> {
|
async loginUser(username: string, password: string, req: Request): Promise<any> {
|
||||||
|
|
||||||
const accessToken = req.cookies['access_token'];
|
const access_token = req.cookies?.access_token;
|
||||||
const refreshToken = req.cookies['refresh_token'];
|
const refresh_token = req.cookies?.refresh_token;
|
||||||
|
|
||||||
// if (!accessToken && !refreshToken) {
|
|
||||||
|
|
||||||
const params = new URLSearchParams();
|
const params = new URLSearchParams();
|
||||||
params.append('grant_type', 'password');
|
params.append('grant_type', 'password');
|
||||||
@ -197,34 +303,52 @@ 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 userSession = await this.getUserSession(username)
|
||||||
|
|
||||||
|
if (access_token && refresh_token && userSession.length > 0) {
|
||||||
|
let tokens = await this.getTokenFromRefreshToken(refresh_token);
|
||||||
|
const decodedHeader = jwt.decode(access_token, { complete: true });
|
||||||
|
|
||||||
|
if (!decodedHeader || typeof decodedHeader !== 'object') {
|
||||||
|
throw new UnauthorizedException("Authentication failed")
|
||||||
|
}
|
||||||
|
|
||||||
|
const kid: any = decodedHeader.header.kid;
|
||||||
|
|
||||||
|
const publicKey = await this.getPublicKey(kid);
|
||||||
|
|
||||||
|
const decoded = jwt.verify(access_token, publicKey, { algorithms: ['RS256'] });
|
||||||
|
|
||||||
|
const email = (decoded && typeof decoded === 'object') ? (decoded as any).email : undefined;
|
||||||
|
return { ...tokens, email }
|
||||||
|
}
|
||||||
|
|
||||||
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' },
|
||||||
});
|
});
|
||||||
console.log('first time data ...');
|
|
||||||
|
|
||||||
let k = { ...response.data, email: username };
|
let k = { ...response.data, email: username };
|
||||||
|
|
||||||
return k;
|
return k;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log(error.message);
|
console.log("error while logging : ", error.message);
|
||||||
|
|
||||||
throw new BadRequestException('Invalid username or password');
|
throw new BadRequestException('Invalid username or password');
|
||||||
}
|
}
|
||||||
// }
|
|
||||||
|
|
||||||
// else if (accessToken && refreshToken) {
|
|
||||||
// return { access_token: accessToken, refresh_token: refreshToken, email: username }
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async getUserIdByEmail(email: string) {
|
async getUserIdByEmailX(email: string) {
|
||||||
|
|
||||||
let url = `${this.USERS_URL}?email=${email}`;
|
let url = `${this.USERS_URL}?email=${email}`;
|
||||||
|
|
||||||
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 +363,44 @@ 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async getUserIdByEmail(email: string): Promise<string> {
|
||||||
|
try {
|
||||||
|
const adminAccessToken = await this.getAdminAccessToken();
|
||||||
|
const url = `${this.USERS_URL}?email=${encodeURIComponent(email)}`;
|
||||||
|
const options: AxiosRequestConfig = {
|
||||||
|
method: 'GET',
|
||||||
|
url,
|
||||||
|
headers: {
|
||||||
|
Authorization: `Bearer ${adminAccessToken}`,
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const response = await axios.request(options);
|
||||||
|
|
||||||
|
if (response.status !== 200 || !Array.isArray(response.data)) {
|
||||||
|
console.log("failed to retrieve user-id....");
|
||||||
|
throw new UnauthorizedException("Authentication failed")
|
||||||
|
}
|
||||||
|
|
||||||
|
const user = response.data[0];
|
||||||
|
if (user?.id) {
|
||||||
|
return user.id
|
||||||
|
} else {
|
||||||
|
throw new UnauthorizedException("Authentication failed")
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.log("Error in getUserIdByEmail ...........");
|
||||||
|
if (error instanceof UnauthorizedException) {
|
||||||
|
throw error
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new InternalServerErrorException();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -295,24 +456,28 @@ export class AuthService {
|
|||||||
|
|
||||||
async getAdminAccessToken() {
|
async getAdminAccessToken() {
|
||||||
try {
|
try {
|
||||||
const adminParams = new URLSearchParams();
|
const adminParams = new URLSearchParams({
|
||||||
adminParams.append('grant_type', 'client_credentials');
|
grant_type: 'client_credentials',
|
||||||
adminParams.append('client_id', this.CLIENT_ID);
|
client_id: this.CLIENT_ID,
|
||||||
adminParams.append('client_secret', this.CLIENT_SECRET);
|
client_secret: this.CLIENT_SECRET,
|
||||||
|
});
|
||||||
|
|
||||||
const adminTokenResponse = await axios.post(this.TOKEN_URL,
|
const { data } = await axios.post(this.TOKEN_URL, adminParams, {
|
||||||
adminParams,
|
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
||||||
{
|
timeout: 6000, // optional: add a timeout to avoid hanging requests
|
||||||
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
});
|
||||||
});
|
|
||||||
console.log(adminTokenResponse.data);
|
|
||||||
|
|
||||||
const adminAccessToken = adminTokenResponse.data.access_token;
|
if (!data.access_token) {
|
||||||
|
console.log("failed to retrieve admin access token.....");
|
||||||
|
throw new UnauthorizedException("Authentication failed")
|
||||||
|
}
|
||||||
|
|
||||||
|
return data.access_token;
|
||||||
|
|
||||||
return adminAccessToken;
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log(error.message);
|
if (error instanceof UnauthorizedException) throw error
|
||||||
throw error
|
console.log("Error in getAdminAccessToken");
|
||||||
|
throw new InternalServerErrorException();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -489,10 +654,15 @@ 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');
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const params = new URLSearchParams();
|
const params = new URLSearchParams();
|
||||||
@ -501,6 +671,8 @@ export class AuthService {
|
|||||||
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 +680,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');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,41 +6,49 @@ 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 token found from Request");
|
||||||
|
|
||||||
throw new UnauthorizedException('Authentication failed');
|
throw new UnauthorizedException('Authentication failed');
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
// Decode the token without verifying the signature
|
||||||
const decoded = await this.authService.decodeToken(token);
|
const decoded = jwt.decode(token) as { exp?: number };
|
||||||
request.user = decoded;
|
|
||||||
return true;
|
|
||||||
} catch (err) {
|
|
||||||
console.log("error in jwt-auth guard below decode : ",err.message);
|
|
||||||
|
|
||||||
throw new UnauthorizedException({
|
if (!decoded || !decoded.exp) {
|
||||||
message: 'Invalid Token',
|
throw new UnauthorizedException('Authentication failed');
|
||||||
error: 'Unauthorized',
|
}
|
||||||
statusCode: 401,
|
|
||||||
});
|
const currentTime = Math.floor(Date.now() / 1000); // in seconds
|
||||||
|
|
||||||
|
if (decoded.exp < currentTime) {
|
||||||
|
console.log('Token expired');
|
||||||
|
throw new UnauthorizedException('Invalid Token');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Token is valid and not expired - continue with your normal logic
|
||||||
|
try {
|
||||||
|
const verifiedUser = await this.authService.decodeToken(token);
|
||||||
|
request.user = verifiedUser;
|
||||||
|
return true;
|
||||||
|
} catch (error) {
|
||||||
|
if (error instanceof UnauthorizedException || error instanceof UE) {
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
throw new InternalServerException();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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',
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user