Firebase AngularJS full data access - angularjs

I'm building an app based on Firebase + AngularJS. I'm using User management service by Firebase. I'm able to get all data for Authenticated user, however, I'm not able to retrieve all user data as admin. How can I get full access to Firebase data.
Thanks!

As Frank mentioned in the comment, Firebase doesn't make user account information available to the admin. Rather, some information is available on the client after authentication and it could be sent to be stored as explicit data in Firebase.
The link Frank provide in the comment explains how to do this.
Applications do not automatically store profile or user state. To persist user data you must save it to your database. The callback function will return an object containing the data for the authenticated user, which you can then write to your database.
Here is the core of the example
var ref = new Firebase("https://<YOUR-FIREBASE-APP>.firebaseio.com");
ref.onAuth(function(authData) {
if (authData && isNewUser) {
// save the user's profile into the database so we can list users,
// use them in Security and Firebase Rules, and show profiles
ref.child("users").child(authData.uid).set({
provider: authData.provider,
name: getName(authData)
});
}
});

Related

MSAL React not showing roles, but they are in the token

I'm trying to implement App Roles in a single-tenant React + .NET Core app of ours. This app has successfully been authenticating users via MSAL, so this is just an incremental addition.
I have the app roles set up in Azure AD, and I have the Authorize attribute with role restrictions working in the .NET back-end, but for some reason I'm unable to get the roles via the react MSAL library, even though when I manually decode the token I see them in there.
I was referring to this MS sample for my code. In my index.js, I have the following:
export const msalInstance = new PublicClientApplication(msalConfig);
const accounts = msalInstance.getAllAccounts();
if (accounts.length > 0) {
msalInstance.setActiveAccount(accounts[0]);
}
Then, in the test page I have, I'm trying to access the roles array in this way (just as a test to print them out):
const TestComponent = () => {
const { instance } = useMsal();
useEffect(() => {
const activeAccount = instance.getActiveAccount();
setTokenRoles(activeAccount?.idTokenClaims?.roles);
// I've also tried:
// setTokenRoles(activeAccount?.idTokenClaims['roles']);
}, [instance]);
return (
<div>
ROLES: {JSON.stringify(tokenRoles)}
</div>
);
};
Unfortunately, tokenRoles is null. When I inspect entire idTokenClaims object, I see all the other claims, but no roles. However, I do see them in the token itself:
{
...
"roles": [
"Packages.Manage"
],
...
}
I'm really hoping to avoid manually decoding the token. There has to be a way to get it out of MSAL.
Jason Nutter's comments provided the answer, and in case this helps others I figured I'd give it a write-up.
Per the MS docs, I put the app roles on the back-end app registration. This is why I am able to have the Authorize(Roles = "Role") attribute work on the back-end. The reason I can see the roles in the access token is that the token is retrieved with the scope for that back-end API. But because I don't have those roles mirrored on the front-end app registration, I don't see anything in the id token.
There would be two options if you wanted to use the Azure app roles:
Mirror the app roles in the front-end app registration. In this way you'd have access to the roles in the id token. This sounds not good because I could foresee a typo or mismatch causing weird issues. I'm sure there might be a way using the Azure API to have a process that would sync the roles, but that's not worth it in my opinion.
Manually decode the access token on the front-end. The cleanest way I could think of to do this would be to create a roles context that would pull an access token, decode it, and store the roles for child components to refer to.
Another alternative would be to manage roles in the app itself. For us, the application in question is single-tenant, so there's not much need to do that. However, we do have a multitenant app we are moving to MSAL, and in that case we will already need to do things like validate that the tenant is authorized, and we will need more granular permissions than what this internal app needs, so we will likely have role system and have the front-end retrieve role and profile data from the back-end upon authentication through MSAL.
EDIT: What I ultimately did...
I did indeed keep the roles in the back-end only, then created a user context object that the front-end would retrieve. This user context includes the app roles, as well as other convenience data points like nickname, and is used by a React context and provider that I wrap my app in.

IdentityServer4: How to set a role for Google user?

I have 3 applications:
An IdentityServer4 API which provides Google authentication and also provides an access token to authorize the resource API.
A simple Resource API which provides some data from DB.
A simple Client in React which have 4 buttons:
Login, for Google auth
Logout
Get data - a simple request with the access token to the Resource API and gets the data from Db
Get user data - returns user profile and token (for debug purpose)
I didn't put any sample code because my problem is not code related, it's knowledge that I'm missing and I ask for guidance.
The workflow is working just fine: the user press the Login button, it is redirected to IdentityServer4 API for Google Auth. From there it is redirected to a Callback Page from the Client and from there to the Index page. I receive the user data and the token, I can request data from the Resource API and it's working.
My problem is: How do I give a Role to the Google Users ?
I don't have users saved in DB. I want three types of Users: SuperAdmin, Admin, Viewer and each of these roles have limited Endpoints which can access.
For limiting their access I saw that I can use Claims-based authorization or Role-based authorization.
So, my question is how ca I give a Google User who wants to login in my app, a specific Claim/Role ? What is the workflow ? I must save it first in DB ? Or there exists a service from Google where I can add an email address and select a Role for that address ?
Thank you very much !
After you get the response from Google in your callback you can handle the user and do what ever you want to do with it. Below are the some typical tasks that you can do in callback that I took from documentation page of identityserver4 link:
Handling the callback and signing in the user
On the callback page your typical tasks are:
inspect the identity returned by the external provider.
make a decision how you want to deal with that user. This might be
different based on the fact if this is a new user or a returning
user.
new users might need additional steps and UI before they are allowed
in.
probably create a new internal user account that is linked to the
external provider.
store the external claims that you want to keep.
delete the temporary cookie
sign-in the user
What I would do is creating an new internal user account that is linked to the external provider and add a role to that user.
If you don't want to save users in db, you can add an extra claim to user in callback method and use that claim in token. and i think this link will help with that.

Do you need firebase admin sdk when creating admin web?

I'm currently working on a small project using firebase. My team member is working on IOS and android while I'm trying to build a custom admin page using React.
In the app, users can signup with their phone and send a request for permission by attaching few documents.
I have to build an admin page to approve or deny these documents. For that I need to get list of all user from User Collection and view all the documents that was submitted and be able update user field 'isApproved' to true or false.
I was thinking of simply creating a new admin account directly in firebase and use that account to signin to admin page and perform the following actions (manipulate normal user info field). But I found out about firebase admin SDK. Do I need to use this in my case?
I may need to send push notifications to all users signed up and create user, update user, delete user account later on.
Give the situation should I use firebase admin SDK?
Can someone give me advice on how to set up the overall structure?
First things first, you should not use the Admin SDK on frontend. The Admin SDK has privileged access to all Firebase resources and does not follow any security rules either. You should always use Admin SDK in a secure environment like Firebase Cloud Functions or your own server.
I am not entirely sure what actions you need to perform while accepting/rejecting the documents. If you need to read/write a specific part of a database (which only a admin can access) then you can use Firebase security rules. You would have to add a Custom Claim to the admin user or store their UID in a database.
But if you need to do multiple things (maybe sending an email to user, doing some actions using 3rd party API), I'll recommend using a Cloud Functions with the Admin SDK.
How will that work?
You will have to create a Cloud Functions to accept/reject the documents.
When the admin accepts/rejects a document, you can pass details of that user (userID, document info and if the docs were accepted to the
cloud function) to the cloud function and process it over there.
The callable function may look like:
exports.verifyDocs = functions.https.onCall((data, context) => {
const {uid, token} = context.auth
if (!uid) return "Unauthorized"
if (!token.admin) return "Forbidden"
//The user is an admin
//Do database updates
//Any third party APIs
});
If you use callable functions, Firebase will automatically add auth info of the user calling that function. In the example above, I've assumed the user will have an admin custom claim but if you want to keep things simple based on UIDs you can do so by:
const adminUIDs = ["uid1", "uid2"]
if (!adminUIDs.includes(context.auth.uid)) return "Forbidden"
To call the function from your React app:
const verifyDocs = firebase.functions().httpsCallable('verifyDocs');
verifyDocs({ userID: "userID", text: messageText })
.then((result) => {
// Read result of the Cloud Function.
});
Any thing you pass in the function above will be available in your cloud functions in the 'data' parameter.

saving userType in ReactJs thorughout the session

I am using ReactJs and Nodejs with mysql as my backend, I am maintaining user session via express-session and setting cookie header in my browser. The problem is that I want to display components based on role (eg.admin or user). I am sending the userType from database to React app,in response to the successful login.
How can I maintain and store this userType througout the session so that I can manage my roles.
I dont think local Storage is a good option.
P.S: I have also key:value pair of userType inside the cookie which I am receiving in my browser.but I dont know how to extract userType from the cookie
If you are having a single cookie, ie userType, you can simple do this in componentDidMount or any other applicable control location:
let userType = document.cookie.split("=")[1]
console.log(userType) //your cokkie value
Else, if there are many cookies, you can follow this:
var cookies= {};
document.cookie.split(/\s*;\s*/).forEach(function(pair) {
pair = pair.split(/\s*=\s*/);
cookies[pair[0]] = pair.splice(1).join('=');
});
console.log(cookies.userType)
Storing in a cookie/local storage is fine you just have to make sure the user is authenticated server-side for a certain privilege.

How To Sign Up A New User To My Website Using Facebook

I have a relatively simple question that I am having trouble finding the answer to. I want to set up a way for users to sign up for and log into my site using Facebook. I have been through tutorials which show me processes I need to go through in order to enable my website to communicate with Facebook.
My question is: Once I can communicate with Facebook, how do I then sign a user up permanently on my site? Do I pull information about the user from Facebook and just create a profile for them on my site using that information? Wouldn't I need to then associate that user's unique Facebook ID with the profile I create for them on my website. It seems like I will have to alter my databases in order to accommodate logging in through Facebook. Am I on the right track?
You can authorize/reauthorize a User with Facebook even without any Database, but if you want to store data for the User (name, email, ...) or connect it to an existing User account in your Database, you can store the unique ID.
Use FB.login to authorize with Facebook and FB.getLoginStatus to refresh the User session and to check if a returning User authorized your App already. The User ID is in the callback response of those functions, for example:
FB.getLoginStatus(function (response) {
if (response.status === 'connected') {
//user is authorized
console.log(response.authResponse.userID);
} else {
//user is not authorized or not logged in on facebook
}
});
Careful though, it is an "App Scoped ID" and only valid for one specific App. See changelog for more information: https://developers.facebook.com/docs/apps/changelog
Btw, hereĀ“s an article about Login with the JavaScrip SDK: http://www.devils-heaven.com/facebook-javascript-sdk-login/

Resources