Im trying to refresh the jwt token with cognitoUser.refreshSession, everytime I log in it simply refreshes the login page and asks me to sign in again
I have written up some code from various examples I have found but still struggle to get it going. If anyone has any suggestions I would welcome them:
Code as follows:
import axios from 'axios';
import { Auth } from 'aws-amplify';
const httpClient = axios.create(
{ baseURL: process.env.VUE_APP_API_BASE_URL }
);
const refreshToken = async function() {
try {
const cognitoUser = await Auth.currentAuthenticatedUser();
const currentSession = await Auth.currentSession();
cognitoUser.refreshSession(currentSession.refreshToken, (err, session) => {
console.log('session', err, session);
return Auth.user.signInUserSession.idToken.jwtToken
});
} catch (e) {
console.log('Unable to refresh Token', e);
}
}
httpClient.interceptors.request.use(
config => {
const idToken = refreshToken()
config.headers.Authorization = idToken;
return config
}, error => Promise.reject(error))
export default httpClient;
Related
Is there a way to get the id token from firebase 9 directly in the axios interceptor? It was possible with firebase 8.
import axios from "axios";
import config from "../config";
import { getAuth, getIdToken } from "firebase/auth";
const API = axios.create({
responseType: "json",
baseURL: config.ApiUrl
});
API.interceptors.request.use(async (request) => {
const auth = getAuth();
const { currentUser } = auth;
request.headers = {
Authorization: `Bearer ${await currentUser.getIdToken()}`,
};
return request;
});
currentUser is null first because it is loaded async by firebase. How can I access it directly without always having the problem that the first time it crashes because the user is not loaded yet?
Thank your for your help.
You can create a function that waits for onAuthStateChanged() to load auth state and returns a promise containing user's token. Try:
const getUserToken = async () => {
return new Promise((resolve, reject) => {
const unsub = onAuthStateChanged(getAuth(), async (user) => {
if (user) {
const token = await getIdToken(user);
resolve(token)
} else {
console.log("User not logged in")
resolve(null)
}
unsub();
});
})
}
API.interceptors.request.use(async (request) => {
const token = await getUserToken();
if (token) {
request.headers = {
Authorization: `Bearer ${token}`,
};
} else {
// prompt user to login?
}
return request;
});
Make sure you have initialized Firebase SDK before using getAuth(). I recommend creating a different file firebase.js, initialize required services and exporting the instances as explained in this answer.
I have all my functions based views on django protected with #permission_classes([IsAuthenticated]) so I have to send a JWT as Bearer token on every request.
In the first version I was using this code:
import axios from 'axios';
import { decodeUserJWT } from '../../extras'
const user = JSON.parse(localStorage.getItem("user"));
var decoded = decodeUserJWT(user.access);
var user_id = decoded.user_id
const instance = axios.create({
baseURL: 'http://localhost:8000/api',
headers: {Authorization: 'Bearer ' + user.access},
params: {userAuth: user_id}
});
export default instance;
Everything was working fine.
But then I added interceptors so I could handle the refreshToken process:
const setup = (store) => {
axiosInstance.interceptors.request.use(
(config) => {
const token = TokenService.getLocalAccessToken();
if (token) {
// const uid = await decodeUserJWT(token);
config.headers["Authorization"] = 'Bearer ' + token;
// config.headers["userAuth"] = uid;
}
return config;
},
(error) => {
return Promise.reject(error);
}
);
const { dispatch } = store;
axiosInstance.interceptors.response.use(
(res) => {
return res;
},
async (err) => {
const originalConfig = err.config;
if (originalConfig.url !== "/auth/token/obtain/" && err.response) {
console.log("TOKEN INTERCEPTOR");
// Access Token was expired
if (err.response.status === 401 && !originalConfig._retry) {
originalConfig._retry = true;
try {
const rs = await axiosInstance.post("/auth/token/refresh/", {
refresh: TokenService.getLocalRefreshToken(),
});
const { access } = rs.data;
dispatch(refreshToken(access));
TokenService.updateLocalAccessToken(access);
return axiosInstance(originalConfig);
} catch (_error) {
return Promise.reject(_error);
}
}
}
return Promise.reject(err);
}
);
};
What happens?
When I add the line config.headers["userAuth"] = uid; the django server console starts showing up that when the react app tries to access the routes it gets a Not Authorized, and when I take that line off de code ... it works fine.
I also tried to pass the param userAuth in the axios.create and keep only the Bearer config inside the interpector code, but still no positive result, the code with the interpector code only works when I take off the userAuth line from axios.
Any ideia on why this is happening and how can I fix this?
I am trying to secure the API Route and this API route is called in the Client and Server-side on different pages.
On the test page, it returns 401 error.
On the test2 page, it returns the content well.
I guess it doesn't pass session when I send the http request in the getServerSideProps.
My question is, how do I secure the API routes used on the client and server-side?
/pages/test
import React from 'react';
import axios from 'axios';
import { getSession } from 'next-auth/react';
const Test = (props) => {
return <div>test</div>;
};
export const getServerSideProps = async (context) => {
// it returns session data
const session = await getSession(context);
// it returns error
const res = await axios.get('/api/secret');
return {
props: {
session,
secret: res.data,
},
};
};
export default Test;
/pages/test2
import React, { useEffect } from 'react';
import axios from 'axios';
import { useSession, getSession } from 'next-auth/react';
const Test = (props) => {
const { data: session } = useSession();
useEffect(() => {
const fetchData = async () => {
const res = await axios.get('/api/secret');
console.log(res.data);
};
fetchData();
}, [session]);
return <div>test</div>;
};
export default Test;
/pages/api/secret
import { getSession } from 'next-auth/react';
const handler = (req, res) => {
const { method } = req;
switch (method) {
case 'GET':
return getSomething(req, res);
default:
return res.status(405).json('Method not allowed');
}
};
const getSomething = async (req, res) => {
const session = await getSession({ req });
console.log(session);
if (session) {
res.send({
content: 'Welcome to the secret page',
});
} else {
res.status(401).send({
err: 'You need to be signed in.',
});
}
};
export default handler;
I found a solution.
export const getServerSideProps = async (ctx) => {
const session = await getSession(ctx);
const headers = ctx.req.headers;
if (session) {
const data = (
await axios.get(`${process.env.NEXTAUTH_URL}/api/secret`, {
headers: { Cookie: headers.cookie },
})
return {
props: {
data,
},
};
} else {
return {
redirect: {
destination: '/login',
permanent: false,
},
};
}
};
/pages/api/secret
import { getSession } from 'next-auth/react';
const handler = async (req, res) => {
const { method } = req;
switch (method) {
case 'GET':
return await getSomething(req, res);
default:
return res.status(405).json('Method not allowed');
}
};
const getSomething = async (req, res) => {
const session = await getSession({ req });
// console.log(session);
if (session) {
res.send({
content: 'Welcome to the secret page',
});
} else {
res.status(401).send({
err: 'You need to be signed in.',
});
}
};
export default handler;
There is a specific method to handle request from serverSideProps, better than using useSession (which is meant for client requests)
https://next-auth.js.org/tutorials/securing-pages-and-api-routes#server-side
Best use unstable_getServerSession as mentioned in the documentation example
await unstable_getServerSession(req, res, authOptions)
with the authOptions coming as an export from your [...nextauth].js
I think I am doing everything correctly. But the program is showing "await is a reserved keyword" in signin function. Here is the code:
import axios from "axios";
const signin = async (username, password) => {
try {
console.log("Sign in function called");
const res = await axios.post(`${process.env.baseURL}/auth/signin`, {
username,
password
});
console.log(res.data);
} catch (error) {
console.log(error);
}
};
const logout = () => {
// remove user from local storage to log user out
localStorage.removeItem("jobmanager_user");
};
export const userService = {
signin,
logout
};
I am attempting to store a JWT as a cookie to prevent my Axios call creating a new one each time and making me login every time the app is refreshed
I think I am on the right path using JS-Cookie and setting the cookie to my JWT provided by the API. However I am still redirected on login every refresh. How can I keep the authToken as my original JWT token?
import axiosAPI from 'axios';
import Cookies from 'js-cookie';
let authToken = null;
const axios = axiosAPI.create({
baseURL: `${baseURL}`
});
// User login
export const loginUser = (data) => {
return new Promise((resolve, reject) => {
axios.post(`${baseURL}/jwt-auth/v1/token`, data)
.then((res) => {
if (Cookies.get('token') == null) {
authToken = res.data.token;
} else {
Cookies.set('token', res.data.token);
authToken = Cookies.get('token');
}
// Adds the token to the header
axios.defaults.headers.common.Authorization = `Bearer ${authToken}`;
resolve(res.data);
})
.catch((error) => {
reject(error);
});
});
};
I have also tried this:
import axiosAPI from 'axios';
import Cookies from 'js-cookie';
const authToken = Cookies.get('token');
const axios = axiosAPI.create({
baseURL: `${baseURL}`
});
// User login
export const loginUser = (data) => {
return new Promise((resolve, reject) => {
axios.post(`${baseURL}/jwt-auth/v1/token`, data)
.then((res) => {
if (Cookies.get('token') === null) {
Cookies.set('token', res.data.token);
}
// Adds the token to the header
axios.defaults.headers.common.Authorization = `Bearer ${authToken}`;
resolve(res.data);
})
.catch((error) => {
reject(error);
});
});
};
which fails to log me in altogether