Nextjs router.push() does not correctly redirect - next.js

I'm building a todo app with Next.js, and I'm implementing some protected routes using a JWT token that I get from a backend after login. I store this token in the localStorage and then get it to send it to the backend on certain API calls.
To check if I should redirect a user out from a protected route, I check if the token is present in the localStorage and, if it is not, I redirect the user using router.push(), but it is not working, and I don't understand why, this is my code.
const router = useRouter()
useEffect(() => {
const token = localStorage.getItem('jwt')
const username = localStorage.getItem('username')
if (typeof token === null) {
router.push('/login')
}
getTodos(username, token)
}, [])
The keys are correct, if I login successfully the tokens and username are in local storage.

Related

Next.js SSR with Firebase Auth to authenticate external API using Axios interceptor

My Next.js SSR App will use Firebase Auth to authenticate users. The access token from Firebase Auth will be used to authenticate on an external API.
I have it working in my React App but I am migrating now to Next.js for SSR.
Currently I am struggling with the Axios interceptor... how do I authenticate the user and add the Firebase access token to the request header when on server-side?
I think I need to use cookies?!
High level explanation would sufficient, some code example even better!
edit: I found this article but that would mean I have to add this logic to every single protected route and additionally add the access token to the Axios interceptor for client-side requests, eg. when searching or sending a post request?
export const getServerSideProps = async (ctx: GetServerSidePropsContext) => {
try {
const cookies = nookies.get(ctx);
const token = await firebaseAdmin.auth().verifyIdToken(cookies.token);
// the user is authenticated!
const { uid, email } = token;
// FETCH STUFF HERE!! 🚀
return {
props: { message: `Your email is ${email} and your UID is ${uid}.` },
};
} catch (err) {
// either the `token` cookie didn't exist
// or token verification failed
// either way: redirect to the login page
ctx.res.writeHead(302, { Location: '/login' });
ctx.res.end();
// `as never` prevents inference issues
// with InferGetServerSidePropsType.
// The props returned here don't matter because we've
// already redirected the user.
return { props: {} as never };
}
};

What are access token and refresh token from firebase auth result

I set up my APP and can get an auth result by using firebase.auth.OAuthProvider('google.com'). Inside the returned result, there is an User object that contains refreshToken. Is this the refresh token generated by google.com so I can use it later to refresh an access token which will be used to access gmail? I am talking about this field [google reference].(https://firebase.google.com/docs/reference/js/firebase.User#refreshtoken)
My second question is where is the access token from google.com? Is it the credential.idToken?
const auth = firebase.auth();
var provider = new firebase.auth.GoogleAuthProvider();
const provider = new firebase.auth.OAuthProvider("google.com");
const currentUser = auth.currentUser;
auth.signInWithPopup(provider).then((result) => {
console.log(result.user) // contains `refreshToken`
console.log(result.credential.idToken) // is `idToken` access token?
}).catch((reason) => {
reject(reason);
});

firebase auth share session/token between microservices

I working with firebase auth and I'm a bit confused on how to manage the authentication between different apps, in particular nextjs (main site, that use express too) api and react app (is a kind of dashboard). After reading a bit of documentation what I did (but I'm not sure is the right way) is to get the idToken on the main site with the client side library:
firebase
.auth()
.signInWithEmailAndPassword(email, password)
.then(() => {
const currentUser = firebase.auth().currentUser.getIdToken();
currentUser.then(idToken => {
return axios.post("/auth/login", { idToken });
});
});
and make a request to nextjs/express to create the cookie sessions:
firebase
.auth()
.createSessionCookie(idToken, { expiresIn })
.then(
sessionCookie => {
res.cookie("session", sessionCookie, {
maxAge: expiresIn,
httpOnly: true
});
return res.end(JSON.stringify({ status: "success" }));
},
error => res.status(401).send(error)
);
then when I need to send a request to the api I'll pass the idtoken saved in the cookie and I verify the token in a middleware
const userInfo = await firebase.auth().verifySessionCookie(authToken);
I'm not implemented the react app yet but I think in that I'll just use the clientside library to do everything....My main doubt is the authentication between the nextjs/express and the api, I'm not sure if usin the sessioncookie is the right choise...do I need to send just the tokenId instead of the session cookie? do you have any suggestions?

Forwarding auth token through API

My team is in the process of migrating away from directly read/writes to and from firebase RTDB for our mobile and web app, to a more classic server/client model.
In doing so, I wanted to see if there was a mechanism to forward a users firebase auth token through our server API into the call to the DB. The purpose of this is so that my security rules could apply to the auth token of the user request, and I wouldn't have to write a layer to manage user data access, instead relying on firebase to handle it for me.
So you want to firebase to check before user accessing the data. In that case, you can use firebase getIdToken like below
firebase.auth().currentUser.getIdToken(); // which returns promise.
attach this token to the http headers and then in API Call check the token like below
const validateFirebaseIdToken = (request, response, next) => {
cors(request, response, () => {
if (!request.headers || !request.headers.authorization) {
return response.status(403).send("Sorry! You're not authorized to access this url");
}
const token = request.headers.authorization.split('Bearer ')[1];
return firebase.auth().verifyIdToken(token).then(decodedId => {
request.user = {};
request.user.uid = decodedId.uid;
return next();
}).catch(error => {
console.log(error);
return response.status(403).send("Sorry! You're not authorized to access this url");
});
});
}
This is how you need to check the firebase id token with the API call. Hope this gives you an idea. Feel free to ask if you any doubts

Firebase customToken workflow (ICW Angular2 & Express)

I'm trying to wrap my head around the best way to handle the creation of a customToken with Firebase in a secure way.
This is what I came up with:
The user logs in on the client side with email and password. firebase.auth().signInWithEmailAndPassword(email, password)
Storing the current UID of the user in local storage. localStorage.setItem('uid', response.uid);
Get the JWT token of the current user. firebase.auth().currentUser.getToken(true) and store the token in localStorage localStorage.setItem('token', res)
Make a post call to the server and add the token to Authorization header and send the UID in the body. const headers = new Headers();
headers.append('Content-Type', 'application/json');
headers.append('Authorization', localStorage.getItem('token'));
this.http.post('/api/login', localStorage.getItem('uid'), {
headers: headers
})
On the serverside verify the token const authorization = req.headers.authorization; admin.auth().verifyIdToken(authorization). If valid set the UID this.uid = decodedToken.uid;
Now generate the custom token. Add the additionalClaims const additionalClaims = {
premiumAccount: true }; and call the createCustomToken function. admin.auth().createCustomToken(this.uid, additionalClaims)
Send the custom token back to the client res.status(200).send({
token: customToken
})
On the client side login with the customToken. firebase.auth().signInWithCustomToken(data.token)
Is this summary a good practice or are there better ways to handle this?

Resources