Hacker Newsnew | past | comments | ask | show | jobs | submitlogin
Show HN: Permify 1.0 – Open-source fine-grained authorization service (github.com/permify)
154 points by ucatbas on Aug 25, 2024 | hide | past | favorite | 34 comments
Permify was born out of our repeated struggles with authorization.

Like any other piece of software, authorization starts small but as things grow scaling it becomes a real pain and begins to hinder product development processes.

Ad-hoc authorization systems scattered throughout your app’s codebase are hard to manage, reason about, and iterate on as the company grows.

Also you will need to have more specific access controls as things grow. Traditional approaches like RBAC is inefficient for defining granular permissions such as resource-specific, hierarchical, or context-aware permissions.

Architecture is another problem, in a distributed system you’re going to need a solid plan to manage permissions between your services — all while ensuring high availability and providing low latency in access checks for sure.

We’ve created an open-source project to eliminate the authorization burden for devs.

It’s Permify, an Authorization-as-a-Service to help developers build and manage their authorization in a scalable, secure, and extendable manner.

And last week, we released the first major version (v1.0.0) of it!

Here is how Permify helps you handle authorization.

- Centralize & Standardize Your Authorization: Abstract your authorization logic from your codebase and application logic to easily reason, test, and debug your authorization. Treat your authorization as a sole entity and move faster within your core development.

- Build Granular Permissions For Any Case You Have: You can create granular (resource-specific, hierarchical, context aware, etc) permissions and policies using Permify’s domain specific language that is compatible with RBAC, ReBAC and ABAC.

- Set Custom Authorization For Your Tenants: Set up isolated authorization logic and custom permissions for your vendors/organizations (tenants) and manage them in a single place.

- Scale Your Authorization As You Wish: Achieve lightning-fast response times down to 10ms for access checks with a proven infrastructure inspired by Google Zanzibar, Google’s Consistent, Global Authorization System.

Try it out and send any feedback our way!



Authorization is such a critical yet underappreciated part of system design. It's great to see open source projects tackling this space. I'll definitely be checking this out for my next project. How does this handle multi-region deployments?


Thanks for the support, and don't hesitate to join our Discord community[0] for further questions.

Regarding multi-region deployment, we offer PostgreSQL as the production database option. We support multi-region databases that share the same interface as PostgreSQL, such as Amazon Aurora. CockroachDB is also on our roadmap

[0]https://discord.com/invite/n6KfzYxhPp


Very cool! At first glance this looks a lot like SpiceDB, which is also a Go service based on Zanzibar. Excited to see more entrants in the space, can you talk a bit about what makes Permify special?


Hi thanks for the support! I'm one of the founders at Permify. Both products may seem alike at first glance as you described, but there are a few key differences,

Multi Tenancy: Our architecture is tenancy-based, which means you can create custom authorization models and relation tuples accordingly for different tenants and manage them in a single place. https://docs.permify.co/use-cases/multi-tenancy

Contextual Permissions: we have a functionality that permissions can be dynamically added to access check requests. When you send these relations along with your requests, they get processed alongside existing relations in the database and will return a result: https://docs.permify.co/operations/contextual-tuples

Schema Management: We're taking an approach that help engineering teams to ease and streamline the management and collaboration of their authorization logic. We have features like:

  - Schema Staging: Handle authorization model (schema) changes at different stages and deploy schemas with our GitOps workflow, specifically designed to approve, merge, and monitor schema changes.
  - Partial Schema Update: Gives you the ability to update a schema partially without needing to change the entire schema.
  - Data Bundles: Handle multiple data creation and deletion actions in your applications.


Hey Ege, congratulations on the milestone!


How does this compare to auth0's OpenFGA (based on Zanzibar)?

https://openfga.dev


I think one major difference between the Zanzibar implementations that are out there is support for the 'zookie' consistency token (as mentioned in the original paper). OpenFGA afaik doesn't implement zookies yet[1]. With zookies, each permission write generates a unique token that represents that particular write. Clients can store that token (per resource) and optionally provide it during runtime checks to ensure checks are consistent up to that write. It also helps the system guard against the 'new-enemy problem' (incorrect permissions checks due to permissions changes being read out of order) by ordering writes.

I'd argue that it also unlocks a variety of caching implementations on the Zanzibar server while still allowing clients to specify desired consistency on a per-request/per-resource level. In other words, a Zanzibar implementation with support for zookies can guarantee consistency at a much higher throughput than one that relies on time (second, millisecond delay). This is important for generic 'read after write' scenarios.

Disclaimer: I'm a former founder of Warrant[2] which was recently acquired by WorkOS. Our team has spent a ton of time building our Zanzibar-based authorization service (WorkOS FGA[3]) which supports zookies[4] and other Zanzibar concepts.

[1] https://openfga.dev/docs/interacting/consistency#future-work

[2] https://warrant.dev/

[3] https://workos.com/docs/fga

[4] https://workos.com/docs/fga/warrant-tokens


Forget to mention, thanks for the reminding. Permify also supports zookies[0], here is the official docs for it.

[0]https://docs.permify.co/operations/snap-tokens


Hi there, Ege from Permify here.

Here are the major differences,

- Better Performance: Observed guess, not necessarily a fact: Many folks have come to us from OpenFGA due to latency and performance issues. We’re implementing various levels of caching mechanisms to meet the required performance. We have also documented the differences in caching between us and OpenFGA in the following document: https://permify.notion.site/Cache-Differences-Between-Permif....

- Schema Management: We're taking an approach that help engineering teams to ease and streamline the management and collaboration of their authorization logic. We have features like:

  - Schema Staging: Handle authorization model (schema) changes at different stages and deploy schemas with our GitOps workflow, specifically designed to approve, merge, and monitor schema changes.
  - Partial Schema Update: Gives you the ability to update a schema partially without needing to change the entire schema.
  - Data Bundles: Handle multiple data creation and deletion actions in your applications.


How does an external authorisation service work without the knowledge contained in the application’s database? And vice versa, how does the application make the efficient correct queries from its database when the authorisation information has been externalised?


This is the single-biggest drawback to purely Zanzibar-based architectures. The problem with requiring the authorization system to own all authorization data is that there’s really very little pure authorization data in any application. The majority of it is just application data that is sometimes used to make authorization decisions.

Here's a technical post that details these implications in practice: https://www.osohq.com/post/authorization-for-the-rest-of-us

And another post that describes an alternative approach, Oso: https://www.osohq.com/post/local-authorization

(Shocker: I'm cofounder/CEO of Oso)


Actually, it also externalizes and centralizes the authorization data, so it won't work without the knowledge contained in the application database that could affect any authorization decision.

Permify provides a Permission Database[0] that unifies the authorization data (as a collection of Access Control Lists - ACLs) in a database of your choice, serving as the single source of truth for all authorization queries and requests via the Permify API.

[0]: https://docs.permify.co/getting-started/sync-data


Let's say I want to use the model outlined in the "File Storage" example. I set up and populate my permission DB accordingly with file permissions, organization and group assignments, etc. I also have an index filled with metadata related to the files that users have uploaded to my service and not just one, but two 500 GB laptop hard drives dedicated to file storage.

User "A" comes along and searches for files matching "ragtime". I can ask the permission DB to return the ID of 1499 files "A" has (directly or indirectly) access to, and also run a free-text search to return cca. 195700 files with a title, description or indexed content that matches "ragtime". But what happens next? Can I return an accurate search hit count or filtered result set to the user from his limited access-point of view? Do I need to move metadata into the permission database to do so?


While we don’t have exact solution or workflow for handling this case, I can suggest an approach that might help.

Assuming that you apply pagination to the search results, you can send the results to Permify one by one, as you'll only be displaying a limited number to the user. Permify is designed to handle millions of requests per second, so this approach won't cause any issues for your specific case.

While this solves the issue, sending multiple checks at once could create a problem as the number of items on the page increases, though it shouldn't be much of a problem even 500 items.


You can do three things according to Openfga of which the basic two are: ask permify for a list kf all accessible files and match them with the search result. This works best if number of hits is large and number of owned files is small. If number of owned files is large and hits is small then you can ask ‘which of these N files does user U have access to’ where you send the list of search hits.


There is one thing I'd like to know about this general approach of centralising permission data. I guess my question applies to Permify as well as to its various competitors:

When objects and relations change in the applications database, then these changes will often have to be reflected in the permissions database as well, and the application must keep things in sync. But this is probably harder as it first seems, in the presence of errors and transaction rollbacks.

What about this case:

- User creates a FOO in the application.

- The app creates an entry in the "foo" table and assigns the user id as owner, and attempts to store various other data.

- The app also creates an entity in the permissions database and assigns the user id as an owner.

- Then further steps are performed, and one of them fails, rolling back the transaction in the application database.

I would assume that the change to the permissions database cannot be rolled back then, so there is now an inconsistency.

What do people typically do about these things?


In a standard relational based databases, the suggested place to write relationships to Permify is sending the write request in database transaction of the client action: such as assigning the user as owner.

If the transaction fails, you should delete the malformed relation tuple from Permify to maintain consistency.

Here's an example of how this might look in code:

```

func CreateDocuments(db *gorm.DB) error {

  tx := db.Begin()
  defer func() {
    if r := recover(); r != nil {
      tx.Rollback()
      // if transaction fails, then delete malformed relation tuple
      permify.DeleteData(...)
    }
  }()

  if err := tx.Error; err != nil {
    return err
  }

  if err := tx.Create(docs).Error; err != nil {
     tx.Rollback()
     // if transaction fails, then delete malformed relation tuple
     permify.DeleteData(...)
     return err
  }

  // if transaction successful, write relation tuple to Permify
  permify.WriteData(...)

  return tx.Commit().Error
}

```

Although this is an anti-pattern, this approach ensures that if the transaction in the application database fails and is rolled back, the corresponding data in Permify is also deleted, preventing inconsistencies.


You call this an anti-pattern (and rightfully so, since cluttering application code like this is a nightmare), but then what is the better pattern? In an app with >100 entities and >500 types of business transactions, many of which can fail in unexpected ways, will I be forced to maintain what was changed in Permify and roll back manually?

If yes, then this is quite a burden and might be a valid reason for not using a separate permissions store. But maybe there are better ways...?


Actually we have webhooks in our cloud offering to streamline and address this. Since this post is about our open source, I didn't mention it as an option. However, if you choose to go with the open source, you would need to maintain it manually as you described. Open to any suggestions on this. We're designing a functionality to add rollback to snapshots[0], but it likely won't be shipped in the near future.

[0]https://docs.permify.co/operations/snap-tokens


One option would be to employ a two-phase commit mechanism that keeps track of all "sub-transactions" and considers a global transaction to be completed when all datastores report back that they are very, very certain that they can commit the changes on their end without any issues. Then it asks each local transaction to actually commit.

XA is such a standard that pops up often when data sources support such a mechanism:

- https://en.wikipedia.org/wiki/X/Open_XA

- https://dev.mysql.com/doc/refman/8.0/en/xa.html

- https://mariadb.com/kb/en/xa-transactions/


I understand. But I'd rather not get into the complexities and new funny failure modes of such a system, so I was hoping for something simpler.


How do you compare to the many other Zanzibar open source implementations like keto, spicedb, topaz, warrant, etc. It seems like it is a crowded space.


Hi I'm one of the founders at Permify. Thanks for bringing up the comparison. I’ve actually put together some documentation[0] that outlines the differences between various Zanzibar implementations, including Keto, OpenFGA, SpiceDB, and Topaz. Planning to add Warrant and others soon as well. Hope that helps.

[0] https://permify.notion.site/Differentiation-Between-Zanzibar...


How does it play with Keycloak's Authorization Services?

Or in other words - why should I choose permify over Keycloak? https://www.keycloak.org/docs/latest/authorization_services/...


Firstly, while IAMs often offer some level of authorization capabilities, they are not as flexible or fine-grained as dedicated authorization systems like Permify.

Therefore, customizing complex permission logic (such as hierarchical relationships, user group, etc.) can be challenging in IAMs. As an example, Keycloak's Authorization Service supports RBAC and ABAC it does not support ReBAC.

Another point is that authorization as a service solutions are focused entirely on authorization. This means they provide not only fine-grained permissions but also tooling and functionality to ease testing and observability of the authorization system.

Also Permify leveraging Google’s Zanzibar scalable data model and unified ACL (Access Control List) approach, enables the creation of a centralized authorization service capable of handling high volumes of data and access checks across your microservices stack.

Still, it's worth mentioning that if you have a basic authorization system or need, it makes total sense to use the solutions you mentioned for handling the authorization part as well. However, if you want to scale your authorization, especially in a microservices environment, I would suggest trying one of the authz providers instead.


Can this be used for "coarse-grained" authorization, like user log-in and sign-up? I'm building a back end for a mobile app in Deno, and really don't think rolling my own (undoubtedly insecure) method is a good idea.

Right now I'm refactoring my app to use Supabase, but encountering some pain in the authorization area.


User log-in and sign-up are considered authentication but from an authorization perspective Permify domain specific language also supports coarse grained roles (RBAC). See following playground example[0]. Also don't hesitate to join our Discord community[1] for further questions.

[0] https://play.permify.co/?s=rbac

[1] https://discord.com/invite/n6KfzYxhPp


Thanks!


So is this something similar to casbin? What are benefits and caveats of permify compared to auth libraries like casbin?


Authorization libraries can be useful but often fall short in key areas. They typically lack fine-grained access control, limiting their ability to handle complex permissions. Casbin does provide RBAC and ABAC but as far as I know they don't support ReBAC.

Libraries was designed to operate directly on an application’s existing data structures without imposing a standardized model for how that data should be organized.

Direct interaction with diverse data structures can lead to inefficiencies and performance bottlenecks. Without a standardized model, the library might not optimize data access and manipulation as effectively as it could with a uniform data structure.

Additionally, they struggle in microservices architectures, creating challenges in maintaining consistent security policies across services. In a microservices architecture, each service might require access to the authorization library, but replicating this library across services can lead to maintenance, synchronization, and consistency challenges.


Can Permify 1.0 be used for multi-tenancy architectures?


You can use Permify for multi-tenant authorization. Specifically, you can create custom authorization schemas and authorization data for different tenants and manage them in a single place.

To learn more, refer to our docs[0]

[0]:https://docs.permify.co/use-cases/multi-tenancy


Permify is a great product solving real auth problems, and the best part? Open source!


been amazing to see the amount of iteration in the product to get to 1.0!




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: