Check if user is logged in React Js - reactjs

Hello guys i have a JWT authentication in my react project i want to make a function to check if the user logged . My login function is like this :
export function login(data) {
const endpoint = '/api/auth/jwt/'
const csrfToken = cookie.load('csrftoken')
let thisComp = this
if (csrfToken !== undefined) {
let lookupOptions = {
method: "POST",
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(data),
credentials: 'include'
}
fetch(endpoint, lookupOptions)
.then(function(response){
return response.json()
}).then(function(responseData){
console.log(responseData)
localStorage.token = responseData.token
localStorage.expires = responseData.expires // Store the token
console.log("Token Stored", localStorage.token)
console.log("Token Expires", responseData.expires)
refreshToken(data) // Put in to the refresh function
}).catch(function(error){
console.log("error", error)
})
}
}
and my function isLoggedIn is like this :
export function isLoggedIn() {
// Check if we have a token stored
if (localStorage.token !== undefined) {
// I also want to check if the token is still work and don't expire
// i have acces to the expiration date like this :
// localStorage.token == > Token Expires 2018-06-19T14:51:59.451703Z in
the console
// How can check if the token still work ?
return true
}
return false
}

Can't you just check the expires property you stored in your local storage and compare it to current Date ?
Other ways to handle it: store the expiration date in the token itself, then use a jwt decoding library to decode the token and extract it from there. If you are using refresh tokens you can simply wait for the server to return a 401 Unauthorized response and send the refresh token to request a new one.

Related

JWT returning false even after logged in

I am trying to create a REACT JS ecommerce website. For auth part I am using JWT in node js. When logging in using api token is generated and user details are stored in db. But when calling an API for checking if jwt is signed in its returning false. The apis are working fine in postman. But when used in js its not working. Its like log in and user detail fetch apis are sending from different sessions. Why this problem is occuring.
async function getUserDetail() {
var url = url_head + "me";
var response = await fetch(url);
const data = await response.json();
console.log(data['success']);
console.log(data)
return data['success'];
}
async function loginUser() {
var url = url_head + "login";
var email = document.getElementById("loginemail");
var password = document.getElementById("loginpass");
if (email.value != "" && password.value != "") {
var data = {
email: email.value,
password: password.value,
};
var response = await fetch(url, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(data),
});
var body = await response.json();
console.log(body);
if(body['success'] == true){
alert('Succesfully LoggedIn.');
window.location.replace('/')
}
else{
console.log(body['message']);
}
} else {
alert("Please fill all the fields.");
}
}
these are the fucntions to call API. APIS are hosted on heroku.
Please help me out
When you login you need to get your jwt token and store it in localStorage.
async function loginUser() {
// ...
var body = await response.json();
localStorage.setItem('token', body.token)
}
Then you take your token from localStorage and send it to your server like this.
async function getUserDetail() {
const token = localStorage.getItem('token')
let res = await fetch(url, {
headers: {
Authorization: `Bearer ${token}`
}
})
let data = await res.json()
}

How to change axios request config?

For each request to the backend, I send an access token. If the token has not passed verification, then I save the config of the original request and make a request to update the tokens. If everything is fine, then I re-send the original request. The problem is that the original request is sent with the old token. Tell me how I can update the value in headers.Authorization?
import axios from 'axios'
import { setAccessToken } from '../store/authSlice'
export const axiosConfig = (accessToken: any, dispatch: any) => {
const API_URL = 'http://localhost:3001/api'
const $api = axios.create({
withCredentials: false,
baseURL: API_URL
})
$api.interceptors.request.use((config) => {
config.headers!.Authorization = `Bearer ${accessToken}`
return config
})
$api.interceptors.response.use(
(config) => {
return config
},
async (error) => {
const originalRequest = error.config
if (error.response.status === 403 && error.config && !error.config._isRetry) {
originalRequest._isRetry = true
try {
const response = await axios.get(`${API_URL}/auth/refresh-tokens`, {
withCredentials: false,
headers: {
Authorization: `Bearer ${localStorage.refreshToken}`
}
})
localStorage.setItem('refreshToken', response.data.refreshToken)
dispatch(setAccessToken(response.data.accessToken)) // new token
return $api.request(originalRequest) // <=== original request with old token
} catch (e) {
console.log('error')
}
}
throw error
}
)
return $api
}
You are using $api.interceptors.response.use() which is on the response not the request. You will not be able to change the Authorization header on a request that has already been sent.
I would use some type of error handler or axios response intercepter to direct user to the login page if they are expired/not logged in. Then I would have an error handler function that can try to attempt a re-authorization then have the error handler function resend the original request that would then have the updated Authorization token. But remember you still cant change the request that has already been sent.
myAxoisInstance.interceptors.request.use(
function (config) {
// This is run on each request so if you have or then update
the token for local storage your next request will get that updated token
const token = localStorage.getItem("token");
if (token) {
//Assign the token to the config
//If you need to send a request here to see if token is valid I don't recommend that. If you are using a JWT token you can check if it is expired here and do something else like a redirect to login.
config.headers!.Authorization = `Bearer ${token}`;
} else {
//Can retrieve and assign token here I typically like to do a redirect here as they are likely not logged or sesson expired. in or something like that. Then allow the sign-in process to add the token to the local storage.
}
return config;
},
function (error) {
return Promise.reject(error);
}
);

How can I use refresh token

I have a get refresh token api like this http://token.net/api/auth/refresh-token . I want to use it in my login function but to be honest I don't know anything about refresh tokens. how can I implement the refresh token into this.
LoginAuth.js
export const useLogin = () => {
const LoginAuth = async (data: AuthenticationProps) => {
await axios.post(`client.com/auth/login`,
{
email: data.email,
password: data.password,
},
{
headers: {
"Content-Type": "application/json",
Accept: "application/json",
}
}
)
.then((res) => {
if(res.status === 200) {
console.log("works");
}
}, (err) => {
console.log(err);
})
}
return {
LoginAuth,
}
}
Refresh token is used to generate new access token for an application. If the access token has an expiration date, once it expires, the user would have to authenticate again to obtain an access token.
Steps:
After successful login response, store token in localStorage.
Add axios response interceptor method axios.interceptors.response to call refresh_token API and update localStorage with new access_token.
whenever token will get expired, API call will returnINVALID_TOKEN code in response and refresh_token API will be called.
Now, further any API will be called with new refreshed token.

How to use refresh token in reactjs

I am working on a admin app in reactjs which uses redux for state management. In my app when user log in it gets access_token and refresh _token. access_token which gets expired after 5 min. after 5 min token becomes invalid to make any api endpoint request.
I want to know how am I suppose to use this refresh_token to update my access_token which is stored in localStorage of the browser. I had no idea about this refresh_token before this. This is how I make login request and save my access_token and refresh_token.
authentication:
export const Authentication = async(payload) =>{
try{
const response = await fetch(`${generalConfig.baseURL}/oauth/token`, {
method: 'POST',
cache: 'no-cache',
headers: {
'Authorization': `Basic ${btoa("topseller:topseller")}`,
'Accept': '*/*',
// 'Content-Type': 'multipart/form-data',
'accept-encoding': 'gzip, deflate',
},
body: payload
})
.then((response)=>{
console.log(response)
return response.json()
},err=>{
console.log(err,'############')
})
console.log(response,'#########')
return response;
}catch(err){
console.log(err,'############')
}
}
authentication.action:
export const getAccessToken = (dataToSend) => async (dispatch) => {
try {
var formData = ConvertToFormData(dataToSend);
const authResponse = await Authentication(formData);
<-- See above about this Authentication function
const response = await fetch("http://api.smartocart.com/userType", {
method: "GET",
cache: "no-cache",
headers: {
Authorization: `Bearer ${authResponse.access_token}`,
},
});
const payload = await response.json();
if (payload.status === "admin") {
SaveToLocalStorage("access_token", authResponse.access_token);
SaveToLocalStorage("refresh_token", authResponse.refresh_token);
dispatch({
type: GET_ACCESS_TOKEN,
payload: {
access_token: authResponse.access_token,
refresh_token: authResponse.refresh_token,
},
});
} else {
dispatch({
type: ERROR_ACCESS_TOKEN,
buttonPressed: true,
});
}
} catch (exception) {
console.log("Log In again");
}
};
I did read about this in some of the blog post but i did get this. https://nmajor.com/posts/access-and-refresh-token-handling-with-redux
Any help would be highly appreciated.
You can add token expiry time validation on app.js so if you reload you application or move to next page or if you make api call it will check token expiry time validation always if token expired it will make call to fetch update token
check below example : i gave example with react axios
axios.interceptors.request.use(async (config) => {
const expireAt = localStorage.getItem('expiresAt');
let token = localStorage.getItem('authToken');
if (dayjs(expireAt).diff(dayjs()) < 1) {
const data = onGetForcedToken();
token = typeof data === 'string' ? data : await data();
}
// setting updated token
localStorage.setItem('authToken', token);
return config;
}, (err) => {
console.log("error in getting ",err)
});
If you are using Axios, you can intercept a request with the help of interceptor and call api to get a new token in case token got expired.
Another approach to get a new token is by periodically calling api after certain interval before the token gets expired.
For example in App.js
// Get new Token
const getNewUserToken = async () => {
const submitUrl = apiRoot + "/v1/user/refreshtoken";
try {
const res = await fetch(submitUrl, {
method: "GET",
headers: {
token: localStorage.getItem("token"),
"Content-Type": "application/json",
},
});
if (res.status === 200) {
const data = await res.json();
localStorage.setItem("token", data.token);
} else {
// New token didnt received.Remove the previous token and user
localStorage.removeItem("token");
localStorage.removeItem("user");
setUser({});
navigate("/");
}
} catch (err) {
console.log(err);
}
};
const intervalRef = useRef();
const getToken = useCallback(() => {
// Get new token if and only if existing token is available
if (localStorage.getItem("token") != null) {
getNewUserToken();
}
}, []);
// Trigger API to get a new token before token gets expired.
useEffect(() => {
const interval = setInterval(() => getToken(), 1000 * 60 * 6); // 6 minutes interval as our token will expire after 7 minutes.
intervalRef.current = interval;
return () => clearInterval(interval);
}, [getToken]);
Hope this will help you to automatically refresh the token without forcing user to login.

How to refresh JWT tokens in React.js Application?

I checked all the similar questions here but none has what I need.
I'm securing the routs in my App and sending the JWT with every request and everything is fine here.
The issue is when the JWT expires, instead of logging out the user, I need to know how to refresh that token and keep the user logged in.
Everyone is talking about creating a "Middleware" that handles that, but no one says how to create that middleware and what's in it?
So, what is the best practice in doing that? Should I check for JWT expiration date before sending any request? or should I wait for a "401" response then try to refresh the token (which I don't know how to do), or what exactly?
If anyone has a working example of such a middleware or a package or a project on Github that can help me with this it would be great.
I'm only interested in the front-end part of the process, what to send from react and what should I expect to receive and what to do with it.
If you are using Axios (which I highly recommend), you can declare your token refreshing behaviours in the response's interceptors. This will apply to all https requests made by Axios.
The process is something like
Checking if the error status is 401
If there is a valid refresh token: use it to get the access token
if there is no valid refresh token: log the user out and return
Redo the request again with the new token.
Here is an example:
axios.interceptors.response.use(
(response) => {
return response
},
(error) => {
return new Promise((resolve) => {
const originalRequest = error.config
const refreshToken = localStorage.get('refresh_token')
if (error.response && error.response.status === 401 && error.config && !error.config.__isRetryRequest && refreshToken) {
originalRequest._retry = true
const response = fetch(api.refreshToken, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
refresh: refreshToken,
}),
})
.then((res) => res.json())
.then((res) => {
localStorage.set(res.access, 'token')
return axios(originalRequest)
})
resolve(response)
}
return Promise.reject(error)
})
},
)
your middelware should look like this block of code (as example you can use whatever you want)
/* eslint-disable */
import request from 'superagent';
function call(meta, token) {
const method = meta.API_METHOD ? meta.API_METHOD : 'GET';
let req = request(method, 'http://localhost:8000/' + meta.API_CALL);
req = req.set({ Authorization: `JWT ${token}` });
req = meta.API_TYPE ? req.type('Content-Type', meta.API_TYPE) : req.set('Content-Type', 'application/json');
if (meta.API_PAYLOAD) {
req = req.send(meta.API_PAYLOAD);
}
if (meta.API_QUERY) {
req.query(meta.API_QUERY);
}
return req;
}
export default store => next => action => {
const state = store.getState();
const token = state.logged && state.logged.get('token') ?
state.logged.get('token') : 'eyJhbGciOiJIUzUxMiJ9';
if (action.meta && action.meta.API_CALL) {
call(action.meta, token)
.then((res) => {
store.dispatch({
type: action.meta.API_SUCCESS,
result: res.body,
});
})
.catch(({ status, response }) => {
if (action.meta.API_ERRORS && action.meta.API_ERRORS[status]) {
return store.dispatch({
type: action.meta.API_ERRORS[status],
result: response.body,
});
}
if (action.meta.API_ERRORS && action.meta.API_ERRORS[status] === '401') {
/*call the refresh token api*/
call(<Your Meta for refreshing>, <expiredtoken>)
.then((res) => {
store.dispatch({
type: action.meta.API_SUCCESS,
result: res.body,
});
})
.catch(({ status, response }) => {
if (action.meta.API_ERRORS && action.meta.API_ERRORS[status]) {
return store.dispatch({
type: action.meta.API_ERRORS[status],
result: response.body,
});
}
throw response;
});
}
throw response;
});
}
return next(action);
};

Resources