-
Notifications
You must be signed in to change notification settings - Fork 169
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
User Roles and Permissions (AUTH_GET_PERMISSIONS) #36
User Roles and Permissions (AUTH_GET_PERMISSIONS) #36
Conversation
Hi @LaszloDev, Thanks so much for the detailed writeup! Glad the package helps you out! This is a great idea, and as I've spent more time in the Firebase ecosystem, I've learnt that UserClaims are the best way to securely connect Permissions to the Firebase user. Although UserClaims are not easy to change on the client (maybe not even possible without the firebase-admin package), this looks like a step towards better permissions. Cheers, |
This has been deployed as version: react-admin-firebase commit: 2efcf09 |
Thanks for merging!
Right, the claims can only be set at a server level and I didn't like the suggestion to use a callable Cloud Function. So I wrote a first version of a Firebase function which allows to set custom claims by editing a Firestore collection. Each document in the Roles collection represents a User and its properties are his roles. The collection is secured by allowing only users with Admin-role to write to. exports.setUserClaimsOrRoles = functions
.firestore.document('config_roles/{userId}')
.onWrite((change, context) => {
const userId = context.params.userId
const changeAfterData = change.after.data()
let data = {}
console.log(`Changing claims for userid: ${userId}`)
if (typeof changeAfterData === 'object') {
data = { ...changeAfterData }
}
// Remove falsy values from object
cleanObject(data)
return admin
.auth()
.setCustomUserClaims(userId, data)
.then(() => {
admin
.auth()
.getUser(userId)
.then(userRecord => {
// The claims can be accessed on the user record.
console.log(
`New claims/roles for user ${userId} are`,
userRecord.customClaims,
)
})
.catch(error => {
console.log(error)
})
})
.catch(error => {
console.log(error)
})
})
function cleanObject(obj: { [index: string]: any }) {
Object.keys(obj).forEach(key =>
obj[key] && key.includes('role_') ? null : delete obj[key],
)
} The user would need to logout and login again to get a fresh Firebase token with the custom claims/roles to work with react-admin. Do you see any problems or optimizations? Otherwise we could put it in the readme with an example how to use Firebase roles with |
Wow, that's actually a brilliant idea! Currently, at my work we invoke cloud functions to modify user claims, but it's tedious and permissions have to be stored in the database as well anyway. I generally don't like Firestore triggers as they are hard to debug and can create a chaotic system if abused (we had like 30 running!). But this looks like perfect application for them! |
Happy to hear you like it. Took me some time and looking at a lot different approaches to come up with it. The only thing I don't like so much is that this needs it own Collection for Cloud Functions to be able to monitor it and have a clean code. Have to check if that works with a sub-collection to have only one config collection within the Firestore. |
The work that is done with this library is a great help for me to connect to my firebase backend.
There are a few parts missing which I encountered, like the possibility to work with user roles and react-admins
permissions
property in connection with the Firebase custom claims. I'm going to try to provide the missing parts which this first pull request.About Firebase custom claims see:
https://medium.com/google-developers/controlling-data-access-using-firebase-auth-custom-claims-88b3c2c9352a
and https://firebase.google.com/docs/auth/admin/custom-claims
Problem
My application does have different user roles and thereby I need to restrict access or disable some resources and views.
Todo so React-Admin provides a
permissions
prop which can be used to dynamically restrict access.https://marmelab.com/react-admin/Authorization.html#restricting-access-to-resources-or-views
Behavior
Returning a single child in the
<Admin />
component does only render the Login view. Every login attempt does automatically dispatch theAUTH_LOGOUT
-action.Solution
The
react-admin-firebase
AuthProvider
does not implement theAUTH_GET_PERMISSIONS
-action as needed to return the permissions to the reducer.https://marmelab.com/react-admin/Authorization.html#configuring-the-auth-provider
Pull request
I implemented the missing action action and added
HandleGetPermissions()
to extract the server side / backend provided user roles inside the Firebase User token as "claims". The implementation is running locally in my application very good and I can set the user roles with a Firebase function for a specific user.Maybe you see other ways to provide user roles into react-admin but this seams to me the most forwards and in alignment with Firebase recommendation for user roles.
Happy to hear your feedback!