Refreshing user auth server side in NextJS? - firebase

I'm trying to refresh the users auth token on the server in NextJS, currently I have the token set in cookies that I access like this:
export async function getServerSideProps(ctx) {
const cookies = nookies.get(ctx);
try {
const client = useClient(cookies.token);
// etc
}
}
unfortunately if the token has expired this will fail with the token has expired error.
I do have access to the refresh token but not sure how to use it, firebase.auth().currentUser is undefined in getServersideProps as well

I had similar issue using NuxtJS and the easiest way is to redirect user to a different page where you can get a new Firebase ID Token on client side and then refresh the cookie. For example, you may redirect to a page something like https://domain.tld/auth/refresh?redirect_uri=/dashboard. The query parameter redirect_uri tells where the user was and must be redirected back after refreshing the token.
If you want to avoid the redirect, you would have to store the "Refresh Token" on your server side. I am not sure how secure that will be but don't store refresh token in cookies. But just in case you are wondering how to get new Firebase ID Token using the refresh token, you can make a POST request to this URL:
https://securetoken.googleapis.com/v1/token?key=FirebasePublicAPIKey
The API key is available in your Firebase Config. The body for this POST request seems to be URL encoded and has grant_type and refresh_token fields.
Here's a cURL request for the same:
curl "https://securetoken.googleapis.com/v1/token?key=firebaseAPIKey" \
-H 'Content-Type: application/x-www-form-urlencoded' \
-X POST \
-F 'grant_type=refresh_token' \
-F 'refresh_token=firebaseRefreshToken'
I just used Chrome DevTools to check how tokens are refresh and found that.
The first method sounds safer to me and I personally use it over storing refresh tokens somewhere on server or cookies. In fact, I use custom JWT tokens from my server in cookies instead of Firebase ID Tokens themselves.

Related

How is this access token stored on the client, in FastAPI's tutorial "Simple OAuth2 with Password and Bearer"

I'm pretty new to FastAPI and OAuth2 in general. I just worked through the tutorial "Simple OAuth2 with Password and Bearer" and it mostly made sense, but there was one step that felt like magic to me..
How does the access token get stored onto the client and subsequently get passed into the client's requests?
My understanding of the flow is that it's basically
User authenticates with their username and password (these get POST'ed to the /token endpoint).
User's credentials are validated, and the /token endpoint returns the access token (johndoe) inside some JSON. (This is how the user receives his access token)
???
User make a subsequent request to a private endpoint, like GET /users/me. The user's request includes the header Authorization: Bearer johndoe. (I don't think the docs mention this, but it's what I've gathered from inspecting the request in Chrome Developer Tools)
The authorization token is then used to lookup the user who made the request in (4)
Step (3) is the part that I don't understand. How does the access token seemingly get stored on the client, and then passed as a header into the next request?
Demo
When you run the code in the tutorial, you get the following swagger docs. (Note the Authorize button.)
I click Authorize and enter my credentials. (username: johndoe, password: secret)
And now I can access the /users/me endpoint.
Notice how the header Authorization: Bearer johndoe was automagically included in my request.
Last notes:
I've checked my cookies, session storage, and local storage and all are empty
The authorization header disappears if I refresh the page or open a new tab
I suspect Swagger is doing something under the hood here, but I can't put my finger on it.
If you need persistence for the token you'd usually use localStorage or similar, but in SwaggerUIs specific case, the authentication information is kept internally in the library.
If you have enabled persistence SwaggerUI will persistent the access token to localStorage:
export const persistAuthorizationIfNeeded = () => ( { authSelectors, getConfigs } ) => {
const configs = getConfigs()
if (configs.persistAuthorization)
{
const authorized = authSelectors.authorized()
localStorage.setItem("authorized", JSON.stringify(authorized.toJS()))
}
}

Redirecting user to a new page after successful login with Firebase

I have a web app and I am using firebase authentication to login/signup our users.
In the past I have used Passport for login in my app which works but you have to maintain your own database and security blah blah... but I can control when my user can visit a page after logging via Passport using middleware like this -
// isAuthentcated is my middleware on server side.
app.get('/home', isAuthenticated,(req,res)=>{
res.render('home');
});
How can I do the same using firebase because there isn't any mechanism to do that. I have read different answers on stackoverflow and most of the pople are suggesting something like below which obviously isn't secure. Anybody can just type home.html and get to the page.
firebase.auth().onAuthStateChanged(user => {
if(user) {
window.location = 'home.html'; //After successful login, user will be redirected to home.html
}
});
Although, I have thought of using firebase-admin sdk token verification and try to follow the suggestion here but I don't know how it can be useful to do that on server side. Do you guys have any suggestions? How do you redirect user to a new page. An ajax post/get request from a client to a route '/home' with a header containing 'Bearer token' just validate the token but doesn't redirect user because it is a ajax call which is meant for updating a portion of a page.
Now, the question really is, Is it even possible to do that with firebase authentication?
If you host your site on App Engine you can send the ID token of the client with the request for the HTML. This could take the form of a cookie, a parameter, or whatever you choose to securely transfer the token from client to server.
Then the server can use the Firebase Admin SDK to verify the ID token, and use whatever logic you need to determine whether the request is authorized.

Firebase auth idTokens

I have read so many articles about firebase auth on web but couldn't find any clear explanation of how idTokens are supposed to be used on the client side. Here is what I know so far
After the user has logged in, we can get the token using the following method and it will automatically refresh the token if it has expired
firebase.auth().currentUser.getIdToken(/* forceRefresh */ true).then(function(idToken) {
// Send token to your backend via HTTPS
// ...
}).catch(function(error) {
// Handle error
});
We can then send this token to our backend where we can use firebase admin SDK to verify the id token and get the user uid.
admin.auth().verifyIdToken(idToken).then(function(decodedToken) {
var uid = decodedToken.uid;
// ...
}).catch(function(error) {
// Handle error
});
Here are the things which I don't understand.
Do I need to call getIdToken() method before each API call to the server to get the idToken?
Firebase documentation says that the token expires after 1 hour. So am I supposed to keep a track of that using localStorage and then reuse the token for 1 hour till it expires and then issue a new one using getIdToken()?
Should I instead create a session on the backend with the uid which won't expire and then use that to verify if the user has logged in or not?
No; as you noted, the token is valid for an hour. You can reuse the same token during that period unless you have a reason to refresh it (for example, if you add custom claims)
Ideally your server will return a 401 Unauthorized or something when the token is invalid. Most REST libraries provide the ability to add interceptors in the request chain, so you can check if you get back a 401 code and only refresh the token when necessary.
There is no need for a backend session unless your business logic requires it. The Firebase library will handle persistence for you.

unable to get push notifications, unauthorized webhook call back error 401

Not able to establish watch channel. getting unauthorized push notification error 401. Done all required settings for web_hook to work.added domain in domain verification tab. Stuck here for weeks. plz help me out. thanks.
first of all you should have a ssl certificate as push notification only work on https:// you can read all about the requirement here https://developers.google.com/google-apps/calendar/v3/push
but the thing missing in the above link is you shoul have the authentication token set on the callback url ( similar to that when you set before calling a google API.. ) and dont forget to take access token from database (assuming that you had it stored at the time of authentication) as system will not read it from session on callback url.
You need to add this value to the headers of your request:
"Authorization: Bearer user_token"
You can get user token with a GET Google_Http_Request to https://www.googleapis.com/oauth2/v3/token
PHP example to get Google token:
Use Google APIs PHP Client library.
$TokenRequest = new Google_Http_Request(
"https://www.googleapis.com/oauth2/v3/token",
"GET"
);
$Token = $Client->getAuth()->authenticatedRequest($TokenRequest);

Not getting into the callback url

I am using oauth in my web application to access Twitter. My problem is i am not getting the token secret and moreover when i run my application it asks the user for authorization request. when the user click "allow', it does not go back to the called url. Infact it shows a blank untitled page with a url having oauth _token value and oauth_verifier value.
Can someone throw light on this.
Before you send users to twitter.com to authorized the app you need to save the request token secret. When the users clicks allow they will return to the callback url you specify. Once there you need to use the request token/secret to get an access token from twitter that will let you perform API requests as a user.
http://dev.twitter.com/doc/post/oauth/access_token

Resources