Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Select an option

  • Save winterdl/6213ea10c92980e559a4fc242555be17 to your computer and use it in GitHub Desktop.

Select an option

Save winterdl/6213ea10c92980e559a4fc242555be17 to your computer and use it in GitHub Desktop.
Firestore Rules
# Firestore Security Rules - Examples
Default: Every resource is locked down by default, and its a redundant rule, but can be a good reminder in the start of rules file
service cloud.firestore {
match /databases/{database}/documents {
match /{document=\*\*} {
allow read, write: if false;
}
}
}
Only authenticated users can read & write to the buckets, cloud storage
service firebase.storage {
match /b/{bucket}/o {
match /{allPaths=\*\*} {
allow read, write: if request.auth != null;
}
}
}
## Authenticated users only
Allow authenticated users to Read and write to all collections and subcollections
service cloud.firestore {
match /databases/{database}/documents {
match /{document=\*\*} {
allow read, write: if request.auth != null;
}
}
}
service firebase.storage {
match /b/{bucket}/o {
match /{allPaths=\*\*} {
allow read, write: if request.auth != null;
}}}
Consider writing rules as you structure your data,
since the way you set up your rules impacts how you restrict access to data at different paths.
## owner of document access
Allow write & delete by the owner of the document only. Where docId for every document in the users collection matches UID from Firebase authentication
service cloud.firestore {
match /databases/{database}/documents {
match /users/{docId} {
allow write, delete: if request.auth.uid == docId;
}}}
## Subcollections
Subcollections are isolated by default from the rules of their parent documents. We can acess them using nested rules
service cloud.firestore {
match /databases/{database}/documents {
match /users/{docId} {
allow read: if request.auth!= null;
allow update: if request.auth == docId;
match /notes/{docId}{
allow read: if request.auth.uid == request.resource.data.userId
allow write, delete: if request.auth.uid == request.resource.data.userId
}
}
}
}
## Example conditions:
// Limit documents per request to 50
allow list: if request.query.limit <= 50
// Make sure that 'myServerTimestampField' was set using a
// server-side timestamp.
request.time == request.resource.data.myServerTimestampField
## Example: Immutable usernames
Allow write: if request.resource.data.username == resource.data.username;
only allow writes if they username already in document matches the one sent with the payload. I.e. not allowed to change the username
export const onCreateUser = functions.auth.user().onCreate(async (user: UserRecord, ctx: EventContext) => {
//.. created user email, displayname, uid, photoURL etc are available in user object
// and we can use it to create a document in another collection or send them welcome email
const userRef = db.collection('users').doc(user.uid);
return userRef.set({
name: user.displayName,
createdAt: ctx.timestamp,
email: user.email,
photoURL: user.photoURL,
uid: user.uid
})
});
## Example: Functions and local variables in rules
match /users/{userId} {
allow read: if isLoggedIn();
allow write: if belongsTo(userId);
}
match /todos/{docId} {
allow read: if resource.data.status == 'published';
allow create: if canCreateTodo();
allow update: if belongsTo()
&& request.resource.data.keys().hasOnly(['text', 'status']);
}
function isLoggedIn() {
return request.auth.uid != null;
}
function belongsTo(userId) {
return request.auth.uid == userId || request.auth.uid == resource.data.uid;
}
function canCreateTodo() {
let uid = request.auth.uid;
let hasValidTimestamp = request.time == request.resource.data.createdAt;
return belongsTo(uid) && hasValidTimestamp;
}
## Check docs in another path/collection
get(/databases/$(database)/documents/users/$(request.auth.uid))
exists(/databases/$(database)/documents/users/$(SOME_DOC_ID))
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read, write: if false;
}
match /messages/{docId} {
allow read: if request.auth.uid != null;
allow create: if canCreateMessage();
}
function canCreateMessage() {
let isSignedIn = request.auth.uid != null;
let isOwner = request.auth.uid == request.resource.data.uid;
let isNotTooLong = request.resource.data.text.size() < 255;
let isNow = request.time == request.resource.data.createdAt;
let isNotBanned = exists(
/databases/$(database)/documents/banned/$(request.auth.uid)
) == false;
return isSignedIn && isOwner && isNotTooLong && isNow && isNotBanned;
}
}
}
return isSignedIn && isOwner && isNotTooLong && isNow && isNotBanned;
## Role based Auth Rules
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /users/{userId} {
allow read: if isSignedIn();
allow update, delete: if hasAnyRole(['admin']);
}
match /posts/{postId} {
allow read: if ( isSignedIn() && resource.data.published ) || hasAnyRole(['admin']);
allow create: if isValidNewPost() && hasAnyRole(['author']);
allow update: if isValidUpdatedPost() && hasAnyRole(['author', 'editor', 'admin']);
allow delete: if hasAnyRole(['admin']);
}
function isSignedIn() {
return request.auth != null;
}
function hasAnyRole(roles) {
return isSignedIn()
&& get(/databases/$(database)/documents/users/$(request.auth.uid)).data.roles.hasAny(roles)
}
function isValidNewPost() {
let post = request.resource.data;
let isOwner = post.uid == request.auth.uid;
let isNow = request.time == request.resource.data.createdAt;
let hasRequiredFields = post.keys().hasAll(['content', 'uid', 'createdAt', 'published']);
return isOwner && hasRequiredFields && isNow;
}
function isValidUpdatedPost() {
let post = request.resource.data;
let hasRequiredFields = post.keys().hasAny(['content', 'updatedAt', 'published']);
let isValidContent = post.content is string && post.content.size() < 5000;
return hasRequiredFields && isValidContent;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment