EDITOR’S NOTE: Welcome to the EMEA Blog Takeover, where our EMEA employees take over the Auth0 blog to share success stories from the region. This week, you’ll meet our thought leaders across the pond, discover some of our most compelling use cases, and read about the trends that influence how we do business.
The Scene
Online media includes a vast world of mostly free and some exclusive paid content, consumed through a plethora of devices. We read the news and listen to music on our phones or smart assistants, skim articles and books on our tablets, and watch movies on our laptops or TVs. More and more, the shape of our devices is changing — from hand-held and large-screen TVs to standalone speakers and connected cars.
In the highly-competitive world of media, understanding the consumer can make the difference between going under or keeping your head above the water. Users need to be able to find media on their devices and consume it at the time they prefer. Keeping the user engaged by offering additional media choices builds loyalty and increases consumption, making room for additional revenue streams.
“The shape of our devices is changing — from hand-held and large-screen TVs to standalone speakers and connected cars.”
Tweet This
Understanding the consumer’s social graph can provide a competitive edge, as it allows media providers to differentiate between different consumers sharing a subscription. This is critical to avoid mixing up personalization efforts, while correctly tailoring media access and subscription usage according to a user’s location, role, and age (e.g. restricting content for younger audiences). Knowing how the consumer relates to others in their network also helps to provide more relevant media recommendations.
Many established media providers are still grappling with digital transformation. While there are innovative ways to design a paywall strategy, paywalls can be challenging as content has increasingly become abundant and often free. A frictionless consumer onboarding process with a low barrier to entry is key, as well as an outstanding initial, and continued, digital customer experience. For this you need a minimal amount of effort needed to setup an account as well as a low commercial threshold, such as a 1-month free or low-entry monthly subscription.
Lots of providers today merely focus on a subscriber account, and perhaps attach some profiles, missing out on truly understanding their consumers. We all know how subscriptions are shared — even with attached profiles it doesn’t provide good separation — and consumers get annoyed when personalisation engines get confused. Furthermore, children grow up, employees move companies, users can become full-blown subscribers themselves, people move across countries … starting with a blank digital profile is painful for all parties involved.
“A frictionless consumer onboarding process with a low barrier to entry is key.”
Tweet This
Authorization Models
As we’ve discussed, it’s important for every user to have his or her own account, or data gets mixed and becomes useless very quickly. Let’s imagine a simple traditional family setup: mom and dad manage the subscription (
1234
), also used by two children, an adult (child_adult
), and a minor (child_minor
). We also have a partner of the oldest child using the subscription (partner_child_adult
). All of them have seperate accounts and we assume they can be recognized seamlessly by all the devices. We’re going to focus on how users are mapped to permissions, i.e. the authorization model used.Note: The examples below are simplified for illustrative purposes. Please reference the linked documentation for more information about the specific features can be used to implement these models.
Discretionary Access Control (DAC)
In a DAC model, all permissions are assigned directly to users, so the model is basically a direct mapping between users and permissions. It holds little information as to why permissions are assigned they way they are, and hence makes it extremely inflexible and hard to manage. In our family example we have five permissions, administration of the subscription (
sub_admin
), access to minor-approved content (content_minor
), access to High Definition streaming any content (content_hd
), access to content for 18 years of age or older (content_adult
), and access to admin-only content (content_admin
). Our example using DAC:
// RULES: DAC // set subscription context.accessToken[`subscription`] = user.subscription; // collect permissions for (permission in user.permissions) context.accessToken.scope.push(permission); // USER: MOM “subscription”: 1234, “permissions”: [“sub_admin”, “content_minor”, “content_hd”, “content_adult”, “content_admin”] // USER: DAD “subscription”: 1234, “permissions”: [“content_minor”, “content_hd”, “content_adult”] // USER: CHILD (ADULT) “subscription”: 1234, “permissions”: [“content_minor”, “content_hd”, “content_adult”] // USER: CHILD (MINOR) “subscription”: 1234, “permissions”: [“content_minor”, “content_hd”] // USER: PARTNER (CHILD ADULT) “subscription”: 1234, “permissions”: [“content_minor”, “content_adult”]
The amount of static decisions to make in this DAC model would be:
complexity_dac = users * (subscriptions + permissions) [users: 10.000, subscriptions: 5.000 & permissions: 5 => 50.050.000]
When faced with an extremely small number of users, subscriptions, and permissions, it might still be manageable. At Auth0, we provide support for DAC by allowing permissions to be stored directly in the user’s account in the
metadata
fields, which can store generic JSON information.Role-Based Access Control (RBAC)
In an RBAC model, an abstraction layer is introduced using the concept of roles or groups. Each role or group can be attached to multiple users on one side and multiple permissions on the other side. In other words, instead of having permissions directly assigned to users, they’re now assigned to roles, which in turn get assigned to users.
Our example using RBAC:
// RULES: RBAC // set subscription context.accessToken[`subscription`] = user.subscription; // collect roles and permissions for (role in user.roles) for (permission in role.permissions) context.accessToken.scope.push(permission); // ROLE: ADMIN “permissions”: [“sub_admin”, “content_admin”] // ROLE: FAMILY (MINOR) “permissions”: [“content”, “content_hd”] // ROLE: FAMILY (ADULT) “permissions”: [“content”, “content_hd”, “content_adult”] // ROLE: FAMILY (EXTERNAL) “permissions”: [“content”, “content_adult”] // USER: MOM “subscription”: 1234, “roles”: [“admin”, “family_adult”] // USER: DAD “subscription”: 1234, “roles”: [“family_adult”] // USER: CHILD (ADULT) “subscription”: 1234, “roles”: [“family_adult”] // USER: CHILD (MINOR) “subscription”: 1234, “roles”: [“family_minor”] // USER: PARTNER (CHILD ADULT) “subscription”: 1234, “roles”: [“family_external”]
The amount of static decisions to make in this RBAC model would be:
complexity_rbac = users * (subscriptions + roles) + roles * permissions [users: 10.000, subscriptions: 5.000, roles: 4 & permissions: 5 => 50.040.020]
When there are significantly fewer roles than permissions, it can vastly reduce the complexity. With Auth0, RBAC can be implemented through the use of roles — permissions can be assigned to roles and roles to users in a static way, either using the Administrator UI or the Management API.
Attribute-Based Access Control (ABAC)
In an ABAC model, policies are introduced that can dynamically determine how permissions are assigned to users based on attributes of the user, but also whatever information is available to the policy engine (like request or context information).
Our example using ABAC:
// RULES: ABAC // set subscription context.accessToken[`subscription`] = user.subscription; // check if admin and add permissions if (user.admin) context.accessToken.scope.push(["sub_admin", "content_admin"]); // check if family and add permissions if (user.external) context.accessToken.scope.push("content"); // check if adult and add permissions if (user.age >= 18) context.accessToken.scope.push("content_adult"); // check if not external and add permissions if (!user.external) context.accessToken.scope.push("content_hd"); // USER: MOM "subscription": 1234, "admin": true, "external": false, "age" : 45 // USER: DAD "subscription": 1234, "admin": false, "external": false, "age" : 47 // USER: CHILD (ADULT) "subscription": 1234, "admin": false, "external": false, "age" : 20 // USER: CHILD (MINOR) "subscription": 1234, "admin": false, "external": false, "age" : 16 // USER: PARTNER (CHILD ADULT) "subscription": 1234, "admin": false, "external": true, "age" : 21
The amount of static decisions to make in this ABAC model would be:
complexity_abac = users * (subscriptions + attributes) [users: 10.000, subscriptions: 5.000, attributes: 3 => 50.030.000]
When the number of attributes is significantly lower than the number of roles or permissions, it can vastly reduce the complexity. Of course, now a dynamic component of policies is introduced. At Auth0, we provide support for ABAC through rules, which are JavaScript snippets that run after login and allow customizing the permissions returned to the applications.
Relationship-Based Access Control (ReBAC)
In a ReBAC model, a graph-based model is introduced between users and subscriptions, and policies dynamically determine how permissions are assigned to users based on relationships of the user. This allows for a lot more expressive and powerful policies, enabling the business to truly understand the user’s environment and act accordingly.
Our example using ReBAC:
// RULES: REBAC // if subscription is managed by user … if (sub:subscription--managed_by-->user:user) context.accessToken[`subscription`] = sub:subscription.number; context.accessToken.scope.push([“sub_admin”, “content_admin”]); // if user is related to admin of sub with max 2 hops … if (sub:subscription--managed_by-->--related_with(2)--user:user) context.accessToken[`subscription`] = sub:subscription.number; context.accessToken.scope.push(“content”); // check if adult and add permissions if (user:user.age >= 18) context.accessToken.scope.push(“content_adult”); // if user is related to admin of sub with max 1 hop ... for (sub:subscription--managed_by-->--related_with(1)-->user:user) context.accessToken.scope.push(“content_hd”); //RELATIONSHIPS sub:1234--managed_by-->user:mom user:mom--related_with-->user:dad user:mom--related_with-->user:child_adult user:mom--related_with-->user:minor_adult user:child_adult--related_with-->user:partner_child_adult // USER: MOM “age” : 45 // USER: DAD “age” : 47 // USER: CHILD (ADULT) “age” : 20 // USER: CHILD (MINOR) “age” : 16 // USER: PARTNER (CHILD ADULT) “age” : 21
Notice that we’ve now stated that everyone who’s related to the admin of the subscription within one hop is considered “close family” and is able to stream content in HD, and everyone who’s related to the admin of the subscription within two hops can access content, allowing all “in-law family” to access content as well, not only childadultpartner.
The amount of static decisions to make in this ReBAC model would be:
complexity_rebac = users * attributes + subscriptions + users * (users - 1) / 2 [users: 10.000, subscriptions: 5.000, attributes: 1 => 50.010.000]
When the number of attributes is significantly reduced through a small number of possible relationships, it can vastly reduce the complexity. Although harder to quantify, it’s clear it provides more power to define generalized policies. As with ABAC, Auth0 supports ReBAC through the use of rules, which can call out to external sources such as a graph database, where the model can be stored and queried efficiently.
The same model could also be used to enrich the information provided back to the application for improved personalization. This allows for a smoother migration of accounts, as social graphs don’t need to change, and can handle more complex setups. For example, an admin on one subscription could also have non-admin access to another subscription.
Conclusion
We looked at four different authorization models to map users to the correct permissions:
Discretionary Access Control (DAC) where permissions are statically assigned to users directly and only proven manageable with extremely small amounts of users, subscriptions and permissions. Supported by Auth0 using metadata on accounts.
Role-Based Access Control (RBAC) where permissions are statically assigned to roles/groups which in turn are assigned to users, vastly reducing complexity when less roles than permissions. Supported by Auth0 using integrated roles.
Attribute-Based Access Control (ABAC) where permissions are dynamically assigned in policies to users based on the attributes or roles/groups of the users, vastly reducing complexity when less attributes than roles/groups and permissions. Supported by Auth0 using rules.
Relationship-Based Access Control (ReBAC) where permissions are dynamically assigned in policies to users based on the relationships or attributes of the users, vastly reducing complexity when attributes are significantly reduced through a small number of possible relationships. Not only does it provide some complexity gains it also allows for far more complex scenarios to be modeled. Supported by Auth0 using rules, calling out to an external graph database.
About Auth0
Auth0 by Okta takes a modern approach to customer identity and enables organizations to provide secure access to any application, for any user. Auth0 is a highly customizable platform that is as simple as development teams want, and as flexible as they need. Safeguarding billions of login transactions each month, Auth0 delivers convenience, privacy, and security so customers can focus on innovation. For more information, visit https://auth0.com.
About the author
Chris Adriaensen
Lead Solutions Engineer