I am working in laravel and firebase as a backend for authentication and data storage. I am using firebase provided js code to signin the user
firebase.auth().signInWithEmailAndPassword(email, password).catch(function(error) {
// Handle Errors here.
var errorCode = error.code;
var errorMessage = error.message;
// ...
});
The problem is that I want to protect my routes from non-authenticated users. How would I check this in my middleware that user is logged in or not because js stores current user's uid in localStorage. Do I have to use a separate database for this purpose? Please help me to go in right direction.
You have to call:
auth.currentUser.getIdToken().then(function(token) {
// The Firebase id token is returned here.
// You will have to send that along your requests to your server.
// Keep in mind this is a short lived token
// You have to call getToken each time you need it in case
// it is auto refreshed underneath.
});
Currently, Firebase provides node.js and java backend libraries to verify the token (to check the user is logged in).
https://firebase.google.com/docs/auth/server
A php library is in the works. When it is ready, it should provide similar functionality for minting custom tokens and verifying Firebase id tokens.
You can simply use this https://github.com/vinkas0/firebase-auth-laravel laravel package to authenticate via firebase
Related
We have built a custom nodejs backend but the authentication is using firebase auth with idtoken, the idtokens expire after 1 hour and the user is automatically logged out. When using firestore this is handled automatically, we have seen solutions that suggest a service worker but that has not worked.
Can someone please suggest a stable solution for this may be a middleware on the backend API's that can regenerate the tokens?
Thanks
The user is not logged out and that is why Firestore keeps working. You can use getIdToken() method again to get user's ID Token and then pass it in API request.
firebase.auth().currentUser.getIdToken(/* forceRefresh */ true).then(function(idToken) {
// Send token to your backend via HTTPS
// ...
}).catch(function(error) {
// Handle error
});
The normal approach (which the Firebase services themselves use too) is to always the current token with each request to the backend service, so that the service has at least 5m to complete the request (which is a lot more than most services need).
If you need a token that can be used for longer, you can consider forcing a refresh of the token before you call the service as Dharmaraj pointed out in their answer.
Alternative, you can switch to using session cookies for the user, which can have an expiration of up to two weeks.
I'm trying to implement Google sign-in and API access for a web app with a Node.js back end. Google's docs provide two options using a combo of platform.js client-side and google-auth-library server-side:
Google Sign-In with back-end auth, via which users can log into my app using their Google account. (auth2.signIn() on the client and verifyIdToken() on the server.)
Google Sign-in for server-side apps, via which I can authorize the server to connect to Google directly on behalf of my users. (auth2.grantOfflineAccess() on the client, which returns a code I can pass to getToken() on the server.)
I need both: I want to authenticate users via Google sign-in; and, I want to set up server auth so it can also work on behalf of the user.
I can't figure out how to do this with a single authentication flow. The closest I can get is to do the two in sequence: authenticate the user first with signIn(), and then (as needed), do a second pass via grantOfflineAccess(). This is problematic:
The user now has to go through two authentications back to back, which is awkward and makes it look like there's something broken with my app.
In order to avoid running afoul of popup blockers, I can't give them those two flows on top of each other; I have to do the first authentication, then supply a button to start the second authentication. This is super-awkward because now I have to explain why the first one wasn't enough.
Ideally there's some variant of signIn() that adds the offline access into the initial authentication flow and returns the code along with the usual tokens, but I'm not seeing anything. Help?
(Edit: Some advice I received elsewhere is to implement only flow #2, then use a secure cookie store some sort of user identifier that I check against the user account with each request. I can see that this would work functionally, but it basically means I'm rolling my own login system, which would seem to increase the chance I introduce bugs in a critical system.)
To add an API to an existing Google Sign-In integration the best option is to implement incremental authorization. For this, you need to use both google-auth-library and googleapis, so that users can have this workflow:
Authenticate with Google Sign-In.
Authorize your application to use their information to integrate it with a Google API. For instance, Google Calendar.
For this, your client-side JavaScript for authentication might require some changes to request
offline access:
$('#signinButton').click(function() {
auth2.grantOfflineAccess().then(signInCallback);
});
In the response, you will have a JSON object with an authorization code:
{"code":"4/yU4cQZTMnnMtetyFcIWNItG32eKxxxgXXX-Z4yyJJJo.4qHskT-UtugceFc0ZRONyF4z7U4UmAI"}
After this, you can use the one-time code to exchange it for an access token and refresh token.
Here are some workflow details:
The code is your one-time code that your server can exchange for its own access token and refresh token. You can only obtain a refresh token after the user has been presented an authorization dialog requesting offline access. If you've specified the select-account prompt in the OfflineAccessOptions [...], you must store the refresh token that you retrieve for later use because subsequent exchanges will return null for the refresh token
Therefore, you should use google-auth-library to complete this workflow in the back-end. For this,
you'll use the authentication code to get a refresh token. However, as this is an offline workflow,
you also need to verify the integrity of the provided code as the documentation explains:
If you use Google Sign-In with an app or site that communicates with a backend server, you might need to identify the currently signed-in user on the server. To do so securely, after a user successfully signs in, send the user's ID token to your server using HTTPS. Then, on the server, verify the integrity of the ID token and use the user information contained in the token
The final function to get the refresh token that you should persist in your database might look like
this:
const { OAuth2Client } = require('google-auth-library');
/**
* Create a new OAuth2Client, and go through the OAuth2 content
* workflow. Return the refresh token.
*/
function getRefreshToken(code, scope) {
return new Promise((resolve, reject) => {
// Create an oAuth client to authorize the API call. Secrets should be
// downloaded from the Google Developers Console.
const oAuth2Client = new OAuth2Client(
YOUR_CLIENT_ID,
YOUR_CLIENT_SECRET,
YOUR_REDIRECT_URL
);
// Generate the url that will be used for the consent dialog.
await oAuth2Client.generateAuthUrl({
access_type: 'offline',
scope,
});
// Verify the integrity of the idToken through the authentication
// code and use the user information contained in the token
const { tokens } = await client.getToken(code);
const ticket = await client.verifyIdToken({
idToken: tokens.id_token!,
audience: keys.web.client_secret,
});
idInfo = ticket.getPayload();
return tokens.refresh_token;
})
}
At this point, we've refactored the authentication workflow to support Google APIs. However, you haven't asked the user to authorize it yet. Since you also need to grant offline access, you should request additional permissions through your client-side application. Keep in mind that you already need an active session.
const googleOauth = gapi.auth2.getAuthInstance();
const newScope = "https://www.googleapis.com/auth/calendar"
googleOauth = auth2.currentUser.get();
googleOauth.grantOfflineAccess({ scope: newScope }).then(
function(success){
console.log(JSON.stringify({ message: "success", value: success }));
},
function(fail){
alert(JSON.stringify({message: "fail", value: fail}));
});
You're done with the front-end changes and you're only missing one step. To create a Google API's client in the back-end with the googleapis library, you need to use the refresh token from the previous step.
For a complete workflow with a Node.js back-end, you might find my gist helpful.
While authentication (sign in), you need to add "offline" access type (by default online) , so you will get a refresh token which you can use to get access token later without further user consent/authentication. You don't need to grant offline later, but only during signing in by adding the offline access_type. I don't know about platform.js but used "passport" npm module . I have also used "googleapis" npm module/library, this is official by Google.
https://developers.google.com/identity/protocols/oauth2/web-server
https://github.com/googleapis/google-api-nodejs-client
Check this:
https://github.com/googleapis/google-api-nodejs-client#generating-an-authentication-url
EDIT: You have a server side & you need to work on behalf of the user. You also want to use Google for signing in. You just need #2 Google Sign-in for server-side apps , why are you considering both #1 & #2 options.
I can think of #2 as the proper way based on your requirements. If you just want to signin, use basic scope such as email & profile (openid connect) to identify the user. And if you want user delegated permission (such as you want to automatically create an event in users calendar), just add the offline access_type during sign in. You can use only signing in for registered users & offline_access for new users.
Above is a single authentication flow.
I'm new to firebase.
In my nuxt js project with multiple pages, firestore rule is set to read or write once request.auth != null.
so if when refresh in a page, auth will be gone and it display error 'permission-denied' in terminal.
i tried Authentication State Persistence LOCAL but it doesn't work.
What is the purpose of using these auth persistence mode ?
firebase.auth().setPersistence(firebase.auth.Auth.Persistence.LOCAL)
.then(function() {
return firebase.auth().signInWithEmailAndPassword(email, password);
})
Auth session is automatically persistent on the frontend of your app, however Nuxt.js contains frontend and backend part. If you are storing user data somewhere on the frontend, you probably need to wait until the user data become accessible.
Example of the listener:
firebase.auth().onAuthStateChanged(function (user) {
if (user) {
console.log('User is logged: ', user);
}
});
However this will make user accessible only on the frontend, if you want to preload data on the backend you would need to store id and refresh token in the cookies or use Nuxt Firebase module which should handle service worker for you.
So, in your case it looks like you are trying to read the data before your user data become accessible (this can be caused by trying to fetch data on the backend).
The question is in the title. I have done some research but it seems like I can't find a solution to extending the life of the login session when using firebase authentication.
Currently, I have a file that logs the user in from the front-end. After logging in with Firebase Authentication, I pass the firebase id token to the server:
//[index.php]
auth.onAuthStateChanged(function(user) {
if (user) {
//Retrieve the firebase id token
user.getIdToken().then((idToken) => {
//Send the idToken to the server
sendIdTokenToServer();
});
} else {
//The user is logged out, redirect to login page
}
});
From the server side, I verify the firebase id token, and assign it to $_SESSION['firsebase_id_token'] if the token is valid.
//[server.php]
//Pseudo verifying the token, if the token is valid, record it
if (verifyToken($token)) $_SESSION['firebase_id_token'] = $token;
Now, from this point on, I am trying to verify the token before processing anything from the server side. For example:
//[test.php]
//Before processing anything, validate the token
if (verifyToken($_SESSION['firebase_id_token'])) {
//Perform an action because the user is still logged in
} else {
//Redirect the user to login page because they are logged out/the token cannot be verified
}
I am not certain this is the right approach to the problem (so please suggest the correct approach), they are just what I think is right when reading the documentation. All I want to do is to verify the user (that logged in from the client side) from the server side before performing any administrative tasks. The problem is after a very short period of time, the $token isn't valid any more, so the request cannot be made.
How do I extend the firebase id token session from the client side?
Instead of using onAuthStateChanged, which is only triggered when the user signs in or out, you should be using onIdTokenChanged, which is triggered whenever the user's auth token is refreshed (every hour automatically, or on demand when you call getIdToken(true)).
Is there any way to restrict access to a given url/route in a Parse CloudCode application?
app.get( '/', function ( req, res )
{
res.render('home');
} );
// only allow access to this 'route' if the user making the request is an admin
app.get('/admin', function(req, res)
{
var user = Parse.User.current();
// user is always null. No way to check their user privileges.
res.render('admin');
});
The problem as I see it, there is no way to access the Parse.User.current(), or request user in main.js file. Creating and then accessing an 'isAdmin' CloudCode function from the client seems the wrong way to prevent access by unauthorised users to urls.
Thanks in advance.
I couldn't comment on your post due to my low point. But have you tried on This documentation?
Your have to use parse made middleware for its express cloud : parseExpressCookieSession and parseExpressHttpsRedirect. Then you can access user data easily with Parse.User.current() in cloud code.
You can see the sample code on Parse SDK reference #parseExpressCookieSession
USER SESSION MANAGEMENT
You can add Parse.User authentication and session management to your
Express app using the parseExpressCookieSession middleware. You just
need to call Parse.User.logIn() in Cloud Code, and this middleware
will automatically manage the user session for you.
You can use a web form to ask for the user's login credentials, and
log in the user in Cloud Code when you receive data from this form.
After you call Parse.User.logIn(), this middleware will automatically
set a cookie in the user's browser. During subsequent HTTP requests
from the same browser, this middleware will use this cookie to
automatically set the current user in Cloud Code. This will make ACLs
work properly in Cloud Code, and allow you to retrieve the entire
current user object if needed.
...