What Is Fine Grained Authorization?
Authentication is about who the user is. Authorization is about what they can do.
Historically, software applications have, in general, handled authorization in a coarse grained manner. A user has one or more roles in an application, which grants them permissions to perform certain actions across the application. This worked well for a while because users didn't create content in systems. As social and work collaboration applications become mainstream, a different kind of authorization became necessary: fine grained authorization.
An application implements fine grained authorization when it can determine a user's permission to perform actions on any object in the application, and users can create objects in the application and manage permissions to those objects.
This is "fine grained" because there is no lower limit to the granularity at which builders of the system can make authorization decisions. It is up to the builders of the system to determine how granular they want authorization to be, and up to the users of the system to determine who has specific permissions on objects.
Why Is Fine Grained Authorization Important?
Fine grained authorization is increasingly becoming a critical element in software. For example:
- Collaboration and social features are things users expect, such as the ‘Share’ button you see in so many applications. This applies to both business-related assets, such as documents and project boards, and personal assets like pictures and home IoT devices. Specifically sharing one of these objects with another user is a Fine Grained Authorization use case.
- Security, compliance, and privacy are musts for any software application from day 1, and authorization is a big part of solving those concerns. In fact, the TOP OWASP 2021 risk is broken access control.
However, solving authorization in an application is not a trivial matter. We believe applications solve authorization correctly if their authorization solution has the following characteristics:
- Reviewable: It should be easy to determine "who can access what," essentially understand the rules used to enforce access control.
- Easy to manage change: Authorization related changes must be explicit and traceable. Change management control for authorization is important.
- Auditable: It should be possible to know what happened with regards to authorization, in essence "who tried to access what, and when?".
- Reliable: Authorization decisions are made as part of most flows/requests, so authorization components need to always be running and returning the expected results.
- Fast: Authorization decisions are made as part of most flows/requests, so they need to be fast. If authorization decisions are slow, then the end-user experience is slow as a whole.
Implementing all of the above is complex, even with expertise. So we looked at how we could solve authorization for our customers, and allow them to focus on their core business. This is what led us to create Auth0 Fine Grained Authorization.
What Is Auth0 Fine Grained Authorization?
Auth0 Fine Grained Authorization (FGA) is a SaaS to solve fine grained authorization at scale for developers. It is inspired by Google Zanzibar, the system Google uses to solve authorization across all their products, such as Google Drive, Youtube, Google Cloud, and others.
Auth0 FGA does not require you to be using Auth0 already. You can use Auth0 FGA with any identity provider: your own user database (e.g. MySQL, PostgreSQL), Auth0, Okta or anything else.
Auth0 FGA centralizes your authorization. It becomes your "authorization (micro)service" if you will. It's a single place for you to define your authorization model, store your authorization data and make your authorization decisions, across all your apps and products.
Centralizing your authorization logic and decisions into a single service that has the flexibility to handle use cases across your different products gives you distinct advantages:
- Simplify security auditing: Explicit authorization rules are easier to audit by internal and external parties.
- Lower costs: Standardizing how authorization is done across your company makes it easier for developers to switch teams.
- Deliver faster: You’ll be able to ship features and products faster, as the system is easily extensible to new requirements.
- Security logging: The Auth0 FGA service generates logs for all operations out-of-the-box, both reads and writes.
- Empower your users: Allow users to take control of granting access to their data directly in your application.
- Fast and reliable at scale: A centralized service dedicated to fine grained authorization should scale as your business and products grow. Since Auth0 FGA specializes in fine grained authorization and nothing else, it can be particularly optimized for access control patterns and use cases, improving the latency and reliability of your authorization approach.
Auth0 FGA supports granting access at an atomic object level in any system, easily enabling collaboration between users, going far beyond typical role-based access control (RBAC). It also supports building custom roles into any system, empowering your customers to define how to manage access. Auditing capabilities provide fundamental building blocks for security and compliance teams. The more we’ve spoken to customers about it, the more we’ve learned just how many use cases it can solve for.
Organizations like AirBNB and Carta have built Zanzibar-like systems to solve their authorization needs. We don’t think organizations should build the same authorization tooling, again and again, so we set out to build one version everyone can use. We developed Auth0 FGA as a service so you don't have to.
How Do I Get Started?
To start using Auth0 FGA you need to do three things:
- Define your authorization model (docs)
- Write authorization data from your system to Auth0 FGA (docs)
- Add authorization to your API by adding access control checks to your system (docs)
From that point on, all authorization decisions are centralized and made by Auth0 FGA. You can think of it as your "authorization microservice."
A brief example
Let's say you were to start from a Node.js API to manage projects. That API doesn't have authorization capabilities yet, but it does have authentication.
You have an endpoint that would return a particular project given its project ID. In that endpoint, you might have code like the one from the following snippet. The second line verifies the JSON Web Token (JWT) sent as part of the request to perform authentication, using express-jwt.
app.get('/project/:id', jwt({ secret: PUBLIC_KEY, algorithms: ['RS256'] }), // authorize access async function(req, res, next) { // your business logic } );
Now we want to add authorization so only users that can read a project can call this endpoint.
First, we would install and setup the Auth0 Fine Grained Authorization Node.js SDK. You would need to obtain some data from your Auth0 Fine Grained Authorization account, and follow these steps to get it.
const { Auth0FgaApi } = require('@auth0/fga'); const auth0Fga = new Auth0FgaApi({ environment: AUTH0_FGA_ENVIRONMENT, storeId: AUTH0_FGA_STORE_ID, clientId: AUTH0_FGA_CLIENT_ID, clientSecret: AUTH0_FGA_CLIENT_SECRET, }); ... app.get('/project/:id', jwt({ secret: PUBLIC_KEY, algorithms: ['RS256'] }), function(req, res) { // your business logic } );
You would then add a new middleware that calls Auth0 Fine Grained Authorization to perform authorization on every request, after authentication has taken place. You know who the user is (authentication), now you want to check what they can do (authorization):
app.get('/project/:id', jwt({ secret: PUBLIC_KEY, algorithms: ['RS256'] }), async function(req, res, next) { try { const result = await auth0Fga.check({ tuple_key: { user: req.user.sub, relation: 'read', object: `project:${req.params.id}`, }, }); if (!result || !result.allowed) { return res.status(403) .send({ code: 'missing_permissions', message: `ForbiddenError: Not allowed to access object ${req.params.id}` }); } next(); } catch (err) { // handle error return next(err); } }, function(req, res) { // your business logic } );
The key part of the new middleware is this one, where we call the Auth0 Fine Grained Authorization API:
const result = await auth0Fga.check({ tuple_key: { user: req.user.sub, relation: "read", object: `project:${req.params.id}`, }, });
We are conceptually asking the question "can the {user} read project:{id}"?:
- The user identifier is obtained from the JWT sub (subject) claim, as the JWT validation middleware sets all claims for the JWT in the req.user object as properties. Whatever your existing authentication method is, you can easily integrate it with Auth0 FGA.
- The relation is "read" because the endpoint is a GET, it allows the caller to "read" one project. For PUT or PATCH you would use "write".
- The object is made up of the object type (project) and the project ID. The object ID comes from the request parameters (the path). A full URL for the request might be GET {API_URL}/projects/1234, so the object would be project:1234.
You can learn about CHECK requests in depth here.
The previous example is intentionally verbose to show you the inner workings of things. You can imagine having SDKs for any web framework, API Gateway, and even policy languages that easily allow you to configure authorization per endpoint. For example:
app.get('/projects/:id', jwt({ secret: PUBLIC_KEY, algorithms: ['RS256'] }), authorize(req => ({ user: req.user.sub, relation: 'read', object: `project:${req.params.id}` })), function(req, res) { // your business logic } );
What's in the Developer Community Preview?
The Auth0 FGA Developer Community Preview is completely free and includes the features below. This is a chance for you and your teams to try the product out, assess how you'd integrate it with your apps, and give us your feedback.
Management dashboard
The management dashboard (https://dashboard.fga.dev/) allows you to create an account and a store. You can use the dashboard to define your authorization model, write authorization data, and perform authorization checks.
Documentation
We have written extensive documentation (https://docs.fga.dev/) to help you learn the main concepts, get started, and explore advanced use cases.
HTTP API and SDKs
Auth0 FGA is a product built for developers. We’ve created an API for developers to integrate Auth0 FGA into their systems. Everything you can do with the dashboard you can also do with the API.
At launch, we are shipping with SDKs for Javascript and Golang. If you'd like an SDK for another language let us know in Discord. We can easily generate it from our OpenAPI definitions.
What's Next?
We are excited about the capabilities that Auth0 FGA will unlock for our customers. We want to make sure our roadmap items are driven by customer feedback and input. So if you’re interested in the product, please let us know your thoughts by joining our Auth0 Lab community here.
We are also looking forward to the future, especially the "better together" use cases that Auth0 Fine Grained Authorization will enable for both Auth0 and Okta customers.
We hope you'll join us on this journey and are eager to hear your thoughts on what we’ve built so far.
Take a look, try it out at https://auth0.com/developers/lab/fine-grained-authorization, and let's learn together!
About the author
Damian Schenkelman
VP R&D (Auth0Lab)
Damian was one of Auth0's earliest employees. He loves building products for developers and taking things from 0 to 1.
He played key roles in implementing product features and growing the engineering organization in the early stages, and later on defining Auth0's architecture for scale and creating new products. Today he helps shape Auth0's long term strategy and leads Auth0Lab, a small and amazing team doing research and development of forward-looking products.
He spends his spare time with family, and friends, exercising, and catching up on all things NBA.