feat: refresh token added

This commit is contained in:
مهرزاد قدرتی
2025-08-16 14:38:45 +03:30
parent ba73dbf191
commit 0548118208
5 changed files with 122 additions and 8 deletions

View File

@@ -1,4 +1,4 @@
import { getAccessToken } from '@/lib/apiClient';
import { getAccessToken } from '@/features/authorization/api/identityAPI';
import { type PropsWithChildren } from 'react';
import { Navigate } from 'react-router-dom';

View File

@@ -0,0 +1,109 @@
import apiClient from '@/lib/apiClient';
import axios from 'axios';
export interface GenerateToken {
username: string;
password: string;
}
export interface GenerateTokenResponse {
access_token: string;
expires_in: number;
token_type: 'Bearer';
refresh_token: string;
scope: string;
}
const ACCESS_TOKEN_KEY: 'access_token' = 'access_token' as const;
const REFRESH_TOKEN_KEY: 'refresh_token' = 'refresh_token' as const;
const EXPIRES_IN_KEY: 'expires_in' = 'expires_in' as const;
export const generateToken = async (request: GenerateToken) => {
const body = new URLSearchParams();
body.set('grant_type', 'password');
body.set('client_id', import.meta.env.VITE_IDENTITY_CLIENT_ID);
body.set('scope', import.meta.env.VITE_IDENTITY_SCOPE);
body.set('username', request.username);
body.set('password', request.password);
const result = await apiClient.post<GenerateTokenResponse>(
import.meta.env.VITE_IDENTITY_URL,
body.toString(),
{
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
},
);
sessionStorage.setItem(ACCESS_TOKEN_KEY, result.data.access_token);
sessionStorage.setItem(REFRESH_TOKEN_KEY, result.data.refresh_token);
sessionStorage.setItem(
EXPIRES_IN_KEY,
String(Date.now() + result.data.expires_in * 1000),
);
};
export const getAccessToken = () => {
const sessionToken = sessionStorage.getItem(ACCESS_TOKEN_KEY);
if (sessionToken) return null;
const expiresAt = Number(sessionStorage.getItem(EXPIRES_IN_KEY));
const now = Date.now();
if (now < expiresAt) {
return sessionToken;
} else {
return refreshAccessToken();
}
};
const refreshAccessToken = async () => {
const refreshToken = sessionStorage.getItem(REFRESH_TOKEN_KEY);
if (!refreshToken) return null;
const result = await axios.post<GenerateTokenResponse>(
import.meta.env.VITE_IDENTITY_URL,
new URLSearchParams({
grant_type: 'refresh_token',
refresh_token: refreshToken,
client_id: 'harmony_identity', // from your token payload
}),
{
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
},
);
if (result.data.access_token) {
sessionStorage.setItem(ACCESS_TOKEN_KEY, result.data.access_token);
sessionStorage.setItem(
EXPIRES_IN_KEY,
String(Date.now() + result.data.expires_in * 1000),
);
return result.data.access_token;
}
return null;
};
// export const generateToken = (request: any) => {
// const body = new URLSearchParams();
// body.set('grant_type', request.password ? 'password' : 'otp');
// body.set('client_id', import.meta.env.VITE_IDENTITY_CLIENT_ID);
// body.set('scope', import.meta.env.VITE_IDENTITY_SCOPE);
// if (request.phoneNumber) body.set('phonenumber', request.phoneNumber);
// if (request.email) body.set('email', request.email);
// if (request.password) body.set('password', request.password);
// if (request.otp) body.set('otp', request.otp);
// return axios
// .post(import.meta.env.VITE_IDENTITY_URL, body.toString(), {
// headers: {
// 'Content-Type': 'application/x-www-form-urlencoded',
// },
// })
// .then((result) => console.log(result));
// };

View File

@@ -21,6 +21,7 @@ import {
import type { PasswordLoginRequest } from '../../types/userTypes';
import { Icon, useToast } from '@rkheftan/harmony-ui';
import { useApi } from '@/hooks/useApi';
import { generateToken } from '../../api/identityAPI';
export interface EnterPasswordFormProps {
onEditValue: () => void;
@@ -79,6 +80,13 @@ export const EnterPasswordForm = ({
if (!loginWithPassResult) return;
if (loginWithPassResult.success) {
console.log('logged in');
await generateToken({
username: apiRequest.email ?? (apiRequest.phoneNumber as string),
password: apiRequest.password,
});
onLoggedIn(loginWithPassResult.userId);
toast({

View File

@@ -1,9 +1,6 @@
import { getAccessToken } from '@/features/authorization/api/identityAPI';
import axios from 'axios';
// Function to get the token from local storage or state management
export const ACCESS_TOKEN_KEY: 'access_token' = 'access_token' as const;
export const getAccessToken = () => sessionStorage.getItem(ACCESS_TOKEN_KEY);
const apiClient = axios.create({
// Define the base URL for all API requests
baseURL: import.meta.env.VITE_API_URL,
@@ -21,8 +18,8 @@ const apiClient = axios.create({
// --- Request Interceptor ---
// This runs BEFORE each request is sent
apiClient.interceptors.request.use(
(config) => {
const token = getAccessToken();
async (config) => {
const token = await getAccessToken();
if (token) {
// Add the authorization token to the headers
config.headers.Authorization = `Bearer ${token}`;