Firebase custom Token with CustomUserClaims - firebase

I'm can currently succesfully use Firebase admin node sdk to createCustomToken. I know I can pass the token back to the client and using signInWithCustomToken sign in a user and het the UID. However, I am using custom authentication is the first place is because I'm creating sub-users with limited permissions that adminUser allows. I was hoping to use setCustomUserClaims to attach some data to the sub-users so I can show the correct sub-user ui and set correct security rules in database. However I can't seem to figure out how I can set the customClaims beacuse I don't have the sub-user UID until I call signInWithCustomToken on the client. What is the process to do this correctly?
Code I was hoping to run right after creating a customToken for a subUser
admin.auth().setCustomUserClaims(uid, {subUser: true, viewPermisson: true}).then(() => {
});

Related

Incremental authorization with Firebase and GoogleAuthProvider

I'm using Firebase v8 with the GoogleAuthProvider.
Firebase documentation provides the following code to authenticate the user.
firebase.auth().signInWithPopup(provider).then((result) => {
/** #type {firebase.auth.OAuthCredential} */
var credential = result.credential;
// This gives you a Google Access Token. You can use it to access the Google API.
var token = credential.accessToken;
// The signed-in user info.
var user = result.user;
// ...
})
Questions
Google's Using OAuth 2.0 to Access Google APIs article recommends incremental authorization (it's not Firebase, but the recommendation is clear)
It is generally a best practice to request scopes incrementally, at
the time access is required, rather than up front. For example, an app
that wants to support saving an event to a calendar should not request
Google Calendar access until the user presses the "Add to Calendar"
button.
AFAICT, there is no way to achieve incremental authorization with Firebase without re-authenticating the user. While scopes can be added to GoogleAuthProvider using addScope, a subsequent call to signInWithPopup is required (i.e. the user is re-authenticated). Is there any way to prompt only for authorization (e.g. Drive access) without re-authenticating?
Assuming the access token is short lived, can the Google ID token be used to obtain a new access token? Is re-authenticating the user the only way to obtain a new access token?
Is there a way to determine whether the access token has expired?

Firebase create user with customClaim

I'm using the Firebase SDK on a React Native app. I'm authenticating users with onAuthStateChanged - works great.
If it doesn't return a user, they can sign up using their phone number.
For that I use the following on submitting the phone activation code:
...
const credential = firebase.auth.PhoneAuthProvider.credential(
verificationId,
verificationCode
);
await firebase.auth().signInWithCredential(credential).then((response) => {// creating a record on firestore. onAuthStateChanged will be re-triggered and store the user and token in state});
...
I would also like to set custom claims for the user. How do I do that? I cannot use admin SDK since this is the frontend and I also don't want to. I could fire a call to my graphQL to do it, but there is probably a way to add a custom claim in the flow above. How?
There is no supported way to modify custom claims from within a client app. Since custom claims are normally used to give special secure authorizations, it obviously be a security hole to allow user to assign claims to themselves. That's why it's recommended to use the Admin SDK on a secure backend you control.
Custom claims can only be set from a trusted environment. Otherwise anyone could make any claim they want about themselves, which defeats their purpose of securely adding information to a user profile.

Firebase auth customClaims not exists for user created with help of createCustomToken()

I want to store some secret data in user' customClaims. I create a token on server with:
var customToken = createCustomToken(uniqueId, {mySecretData:"VerySecretData"}),
sending it to my app , logging user in with signInWithCustomToken(customToken), and it works fine,
BUT, when i am fetching user later on server by calling admin's getUser(uniqueId) and trying to see its customClaims there is nothing, undefined.
The interesting thing is that i do see this secret data in callable function context' auth property' token object.
Question: why developerClaims are not user' customClaims ?
Reference: https://firebase.google.com/docs/reference/admin/node/admin.auth.Auth#createcustomtoken
Claims added via createCustomToken() only exist in the Auth token issued by the Firebase Auth. They are not stored anywhere beyond that, and getUser() response will not include them. You should use the setCustomUserClaims() to get the behavior you've indicated.

Firebase Auth on Web - How to add spam protection for email/password login

For my website, I want to build my own login form for email/password based authentication using Firebase authentication instead of using FirebaseUI Web. I'll be using createUserWithEmailAndPassword JS function to create new user accounts. But how can I prevent spam registrations? Usually for web based forms, I would use Google Recaptcha and validate the recaptcha on my server. But here, I'm not using my server for creating the user accounts. I'm making a call on the client side to create the user accounts.
Of course, I'll be using email verification in the flow, but how would I prevent bots from creating the accounts in the first place?
I also understand that Firebase has some sort of limit for the number of requests per min from a single IP, but I would like to go further and try to prevent those registrations.
firebase.auth().createUserWithEmailAndPassword(email, password).catch(function(error) {
// Handle Errors here.
var errorCode = error.code;
var errorMessage = error.message;
// ...
});
Thanks.
After 2 years, this question is still valid and as far as I see, it is not possible. You probably do not need an answer to this question anymore but it may help others. Even if you succeed in doing something manually, those js functions will stay there and can be called manually by any user who knows how to do it.
If there are no hidden, top secret options which are not available in the documentation, this is not possible. There is a recaptcha option but it is only for Phone Authentication. So, it seems like you have 2 options.
Ignore and delete users who do not verify their email address.
Disable email option from Firebase console and implement your own
email authentication. Generate your own token and log user into
Firebase with that custom token. https://firebase.google.com/docs/auth/web/custom-auth
I'm following up on frankish's answer. He is totally correct, and I agree I think it's strange that Firebase automatically integrates ReCaptcha when doing phone authentication (and now when doing Phone MFA), but does not provide support in createUserWithEmailAndPassword for passing a recaptcha verifier. Thus, the only way to really get around this is to do something like the following:
Set up ReCaptcha (either V2 or V3) manually on your signup page. Do NOT use firebase. auth. RecaptchaVerifier, that is only for integration with phone authentication.
Immediately after calling createUserWithEmailAndPassword, you need to make a call to your own server that passes up the recaptcha token. There is a Firebase blog post here about how to do that with a Firebase Function: https://firebase.googleblog.com/2017/08/guard-your-web-content-from-abuse-with.html. Note I think it's a bit strange that Firebase documented how to do this with server-side functions but didn't directly integrate this with account creation.
The final point is that in your server-side code, after you make the call to validate the recaptcha token, you need to set a custom claim on the Firebase user with the Firebase Admin API. That claim can be something like recaptchaPassed: true (or false). For details on custom claims see https://firebase.google.com/docs/auth/admin/custom-claims.
After that, you can then do things based on the value of that custom claim. For example you could read that custom claim in other server-side calls, or you can use it in Firestore security rules (good blog post on this, https://medium.com/google-developers/controlling-data-access-using-firebase-auth-custom-claims-88b3c2c9352a). You could also choose to immediately delete the user server-side (using the admin API), if recaptcha verification fails.
Note it's important to understand that there is nothing that guarantees that some malicious script will call your server-side token verification function after the code on the client calls createUserWithEmailAndPassword. Thus, the only way the rest of your code can guarantee that a particular Firebase user passed recaptcha verification is by looking for your custom claim that you set on the user server-side.

Does Firebase support validating a pre-existing facebook access token?

Suppose, for the sake of argument, that I already have a facebook access token for a user of my application. In that case, I don't really need to go through Firebase's whole auth.login("facebook") process, I really just want a trusted server to make sure this is a real access token (e.g. by making a GET request to "https://graph.facebook.com/me" with it) and then to set the Firebase user ID appropriately. Can Firebase do this?
Firebase Simple Login was recently updated to support logging in with an existing Facebook access token.
This means that you can integrate directly with then native Facebook JS SDK in your application, and then pass that Facebook access token to Firebase Simple Login (skipping a second pop-up) via:
var ref = new Firebase(...);
var auth = new FirebaseSimpleLogin(ref, function(error, user) { ... });
auth.login('facebook', { access_token: '<ACCESS_TOKEN>' });
See the access_token option on https://www.firebase.com/docs/security/simple-login-facebook.html for more information.

Resources