Perhaps you’re building a
/profile endpoint, and you’d like to exclude the
profile’s email address unless the current user specifically has access to it.
To build this type of authorization, it often makes sense to use “field-level”
enforcement, by explicitly allowing access to certain fields on your domain
Field-level authorization gives you fine-grained control over who can access exactly what bits of information. In Polar, you can write field-level rules like this:
allow_field(user, "read", profile: Profile, "email") if user = profile.user or user.admin?;
Notice that an
allow_field rule is just like an
allow rule, except that it
takes an additional argument: the field name.
Authorize one field at a time
To enforce field-level authorization in your app, you use the
def get_email(profile, current_user) oso.authorize_field(current_user, "read", profile, "email") profile.email end
will raise an an authorization error when the
user is not allowed to perform the given action. This is an error that you
should handle globally in your app. You can read more details about this in the
Resource-level Enforcement Guide.
Get all authorized fields
Sometimes it is helpful to get all fields that a user can access, and for this
there is a separate method called
# Serialize only the fields of profile that the current user is allowed to read def serialize_profile(profile, current_user) fields = oso.authorized_fields(current_user, "read", profile) profile.slice(*fields) end
authorized_fields method can be used to send only the fields that the user
is explicitly allowed to read, or can similarly be used to filter incoming
parameters from a user for a call to, say, an
update method. In that case, you
might use an
"update" action in the call to
# Filter raw_update_params by the fields on profile that the user can update def filter_update_params(profile, raw_update_params, current_user) fields = oso.authorized_fields(current_user, "update", profile) raw_update_params.slice(*fields) end
Authorizing many fields
Perhaps you have many fields on each object, and you’d like to allow access to
them in groups. For example, a
Profile object might have some public fields,
some fields viewable only by friends, and some fields viewable by admins only.
You can do this with Polar’s
# Allow friends access to friend-only fields allow_field(user: User, "read", profile: Profile, field) if field in ["last_check_in_location", "favorite_animal"] and user in profile.friends; # Allow admins access to admin-only fields allow_field(user: User, "read", profile: Profile, field) if field in ["email", "last_login"] and user.admin?;
Or, if you have trouble listing all fields in your Polar policy files, and you’d prefer to list fields in your application code, you can also use a constant defined on the class, like this:
allow_field(user: User, "read", profile: Profile, field) if field in Profile.FRIENDS_ONLY_FIELDS and user in profile.friends; allow_field(user: User, "read", profile: Profile, field) if field in Profile.ADMIN_ONLY_FIELDS and user.admin?;
Doing so would require you to add the
ADMIN_ONLY_FIELDS constants to your
class Profile ADMIN_ONLY_FIELDS = ["email", "last_login"] FRIENDS_ONLY_FIELDS = ["last_check_in_location", "favorite_animal"] end
That way, you can add new fields and authorize access to them without touching your Polar policy code.
Connect with us on Slack
If you have any questions, or just want to talk something through, jump into Slack. An Oso engineer or one of the thousands of developers in the growing community will be happy to help.