This webpage has a redirect loop when login Facebook by Firebase - firebase

Follow code worked fine with a user already authenticated with my facebook application. But throw a error: "This webpage has a redirect loop" when use a new user.
var myRootRef = new Firebase('https://tttb-demo.firebaseio.com/');
var auth = new FirebaseSimpleLogin(myRootRef, function (error, user) {
});
auth.login('facebook', {
rememberMe: true,
scope: 'email,read_friendlists'
});

I had this problem.
Either:
1) Take your app out of Sandbox mode on Facebook
or
2) Add the user to the list of developers on Facebook.
It's because only you are authorised to access it by default when you create an app in Facebook.

Related

couldn't authenticate spotify in vercel production

I made a spotify clone which have a login,main pages. The user is initially directed to login page (localhost:3000/login) and once the user clicks login button they are taken to spotify authentication callback url (from spotify side, we can login using google, facebook or email etc) and once the user is logged in (successfully authenticated) , spotify provides a token which is used to check if the user is authenticated from client side. If success, the user is taken to the main page (which has all the music in it).
The spotify dashboard takes in redirect url for authentication which in my case its -> http://localhost:3000/api/auth/callback/spotify
This workflow worked perfectly when working and running locally ( localhost:3000 ).
When hosting in vercel,
I created a project in vercel without envs
I took my https://sp-app.vercel.app which is the domain and added to NEXTAUTH_URL into my env, and also added - NEXT_PUBLIC_CLIENT_SECRET, NEXT_PUBLIC_CLIENT_ID and JWT_SECRET
Went to spotify dashboard and editing the redirect url to https://sp-app.vercel.app/api/auth/callback/spotify and saved
redeployed the app from vercel (which gave me a deployent url, but nevermind) and clicked on the domains --> sp-app.vercel.app
The login page came, once I clicked on login button, it loads and stays in login page itself. It isn't moving to my home page nor authenticating but this same code worked locally fine.
Code to understand :
Login button:
{providers !== null && Object.values(providers).map((provider) => (
<div key={provider.name}>
<button onClick={()=>signIn(provider.id, {callbackUrl:"/"})}
>Login with {provider.name}</button>
</div>
}
export async function getServerSideProps(){
const providers = await getProviders(); //getProviders is imported from next-auth
return {
props:{
providers,
}
}
}
middleware:
export async function middleware(req){
const token = await getToken({req,secret:process.env.JWT_SECRET});
const {pathname} = req.nextUrl;
//Allow the request if,
// (1) Its a request for next-auth session & provider fetching
// (2) The token exists
if(pathname.includes('/api/auth') || token){
return NextResponse.next();
}
//Redirect to login if no token or requesting a protected route
if(!token && pathname !== "/login"){
return NextResponse.redirect("/login");
}
}
While I checked with Network tab, I get a session which should log me in and redirect to main page, but it isn't working in vercel deployment.
Hey so first off make sure your NEXTAUTH_URL environment variable is correct. Also check that the redirect URI (from the Spotify developer dashboard) is correct.
After that, add this secureCookie code to the getToken function in the _middleware.js file. So that function should end up looking like this:
const token = await getToken({
req,
secret: process.env.JWT_SECRET,
secureCookie:
process.env.NEXTAUTH_URL?.startsWith("https://") ??
!!process.env.VERCEL_URL,
});
Let me know if this works. I had the same exact issue and this worked for me.

Cannot pass a read permission (email) to a request for publish authorization

I am trying to use Facebook login using Firebase authentication. I have followed whole documentation. Lastly whenever I click the login button it gives an error saying:
Cannot pass a read permission (email) to a request for publish authorization
The line on which it is showing error is:
LoginManager.getInstance().logInWithPublishPermissions(LoginActivity.this,Arrays.asList("email", "public_profile"));
Can someone explain me what I am doing wrong? I have looked other answers also but no help from there.
Use logInWithReadPermissions instead of logInWithPublishPermissions. The error message is very clear about that, you are trying to request read permissions with a function that is being used for publish permissions.
.getInstance().logInWithPublishPermissions is not Firebase Authentication. Signin via federated providers such as Facebook is available via the Firebase JavaScript (web) SDK. See Authenticate Using Facebook Login with JavaScript for details.
firebase.auth().signInWithPopup(provider).then(function(result) {
// This gives you a Facebook Access Token. You can use it to access the Facebook API.
var token = result.credential.accessToken;
// The signed-in user info.
var user = result.user;
// ...
}).catch(function(error) {
// Handle Errors here.
var errorCode = error.code;
var errorMessage = error.message;
// The email of the user's account used.
var email = error.email;
// The firebase.auth.AuthCredential type that was used.
var credential = error.credential;
// ...
});

Firebase Web Admin

First of all, I am using nodejs for the backend. I use firebase hosting and firebase functions to deploy an express() app.
What I am trying to achieve is to make an admin website, which is connected to Firebase. so I have a route /admin/ like this:
adminApp.get("/", (request, response) => {
return response.redirect("/admin/login");
});
Here I basically want to check if a current user is logged in - or not.
I know firebase supports client side authentication using:
firebase.auth().onAuthStateChanged(user => {
if (user) {
} else {
}
});
And using
function login() {
var userEmail = document.getElementById("email").value;
var userPass = document.getElementById("password").value;
firebase.auth().signInWithEmailAndPassword(userEmail, userPass).catch(function(error) {
var errorCode = error.code;
var errorMessage = error.message;
if (error) {
document.getElementById('loginError').innerHTML = `Error signing in to firebase`;
}
});
}
However image this case:
Someone (not an admin) is visiting /admin/some_secret_website/ which he obviously does not have access to.
If I rely on client side authentication, it first loads the entire website and the scripts and then notices - hey I am not authenticated, let me redirect to /login. By then however anyone knows the source code of an admin page.
I'd rather have something like:
adminApp.get("/admin/some_secret_website", (request, response) => {
if (request.user) {
// user is authenticated we can check if the user is an admin and give access to the admin page
}
});
I know that you can get the user's token and validate that token using the AdminSDK, but the token must be send by the client code, meaning the website was already loaded.
I came across Authorized HTTPS Endpoint by firebase, but it only allows a middleware when using a bearer token.
Does anybody know how I can maintain a server side user object to not even return admin html to the browser but only allow access to admins?
Like Doug indicated, the way your admin website/webapp would function with Firebase Cloud Functions (which is effectively a Nodejs server) is that you get the request, then use the headers token to authenticate them against Firebase Auth. See this answer for a code snippet on this.
In your case, I'm thinking you would create a custom claim for an "administrator" group and use that to determine whether to send a pug templated page as a response upon authentication. As far as Authorization, your db rules will determine what said user can CRUD.

Meteor.js google account : filter email and force account choser

In my Meteor.js application, I'm using the accounts-google package in order to be connected with a google account. I have two questions about it.
First, is there a simple way to filter the account used? I would like that the users can connect only with google accounts belonging to my company. Our google account mails end with #mycompany.com. So it would be a simple mail filtering.
I already done that with some post log in hooks but I was wondering if there was a simpler way for doing it.
My second question is how to force the opening of the google account choser. For now, if I try to connect with a wrong google account, and if I only added this account (like in gmail, drive, etc), the google choser doesn't pop and automatically connect with this wrong account. So, in this case, the user is totally blocked (my application disconnect him if he tries to log in with a wrong account but the google account module doesn't propose him to connect with another account).
Thank you for your help.
In order to restrict signup/login to your domain, simply do on the server:
var checkEmailAgainstAllowed = function(email) {
var allowedDomains = ['mycompanydomain.com'];
var allowedEmails = ['otheruser#fromotherdomain.com','anotheruser#fromanotherdomain.com'];
var domain = email.replace(/.*#/,'').toLowerCase();
email = email.toLowerCase();
return _.contains(allowedEmails, email) || _.contains(allowedDomains, domain);
};
Accounts.config({
restrictCreationByEmailDomain: function(email) {
if (!email) {
throw new Meteor.Error(403,'This email address is not allowed');
}
if (!checkEmailAgainstAllowed(email)) {
throw new Meteor.Error(403,'This email domain is not allowed');
}
return true;
}
});
And to login, you'll need on the client:
Meteor.loginWithGoogle({
forceApprovalPrompt: true, //this is what you want, to rerequest approval each time that prompts the google login prompt
loginStyle : "redirect", //or not, depending on your need
requestPermissions : ['profile', 'email'],
requestOfflineToken: true
}, function (err) {
if (err)
// set a session variable to display later if there is a login error
Session.set('loginError', 'reason: ' + err.reason + ' message: ' + err.message || 'Unknown error');
});
Side note:
Alternatively, you can set up your routes so that every time a new route is called, you login, and every time a route is destroyed or on windows's unload, you call logout. This causes login/logout roundtrip everytime the route changes, but you'll make sure that the new user always has a fresh session
Edit:
When you log out of your meteor app, you don't log out of google. That's how oauth works. So, basically, if you want a meteor log out to also log the user out of their google account, so that the next time they come back, they need to provide credentials again, you should do:
Meteor.logout(function(e) {
if (e) {
console.log("Could not log the user out")
} else {
window.location.replace('https://accounts.google.com/Logout');
}
});
This uses the callback of Meteor.logout() so that when the logout is successfull, the user is redirected to google's central account logout url where the user is also logged out of all google services.

Using firebase facebook auth with facebook graph api

I am using firebase facebook simple login.
Is there any way I can use it conjunction with facebook js graph api?
Let say, calling FB.api('xxx', function(){}) ?
Facebook via Firebase Simple Login returns the Facebook access token as part of the payload. You could then use this directly with the Facebook Graph API and their JavaScript SDK:
var ref = new Firebase(URL);
var auth = new FirebaseSimpleLogin(ref, function(error, user) {
if (user) {
var facebookToken = user.accessToken; // <<-- here it is
}
});
// Note: Attach this to a click event to permit the pop-up to be shown
auth.login('facebook');
As you noted, Singly is another great approach that abstracts some of the effort of talking to Facebook, but shouldn't be necessary if your use case is fairly straightforward.
UPDATE
Firebase Simple Login now supports authenticating a user with an existing Facebook access token, meaning that you can easily use the Facebook JS SDK in combination with Firebase Simple Login without asking your users to authenticate twice.
For example, once you have a valid Facebook access token using the Facebook JS SDK:
var ref = new Firebase(...);
var auth = new FirebaseSimpleLogin(ref, function(error, user) { ... });
auth.login('facebook', { access_token: '<ACCESS_TOKEN>' });
See the access_token option at https://www.firebase.com/docs/security/simple-login-facebook.html for more information.

Resources