Join GitHub today
GitHub is home to over 31 million developers working together to host and review code, manage projects, and build software together.Sign up
Build ACL layer #396
From internal spec document:
The single most frequent question I get when I present our platform to developers at meetups and conferences is “how can I use API with my front-end application?”. The answer usually references Publish, a production, Preact-based web app that interacts with API, although not directly.
Current approach: the middleman
Publish users don’t actually interact with API directly. When they sign in with their email address and password, they authenticate with the Publish backend app, which in its turn will communicate with API to understand if the credentials supplied correspond to a valid user. It will do so using a clientId/secret pair, with a full set of permissions, which is never disclosed to the user.
With these credentials, it will send the email address/password pair typed by the user to API to understand whether they match a valid user. This all happens in a hook, containing custom logic that will respond to different types of request (e.g. create user, validate user, sign out) and interact with a users collection created for the effect.
We do this for two reasons:
But it comes with big disadvantages:
This document proposes an update to API with the aim to fix the issues above, in two steps.
Step 1: Build ACL into API
The first step would be to extend the authorisation layer of API to include things like:
The full set of roles/permissions would be stored against every new client created, and that information would be sent back to users whenever they request a bearer token for their respective clients.
(Example of a response to the /token endpoint, listing the user’s permissions)
Step 2: Easier front-end authentication flow
Each end user can get their own clientId/secret pair, which they can then exchange for a bearer token at sign in stage using the application interface (e.g. using an Ajax request). But what should the application do with that bearer token?
Currently, all subsequent requests to API must include that token in the Authorization header, so the application must store it somehow on the client and inject it into every request. A single page application can do this by keeping the token in memory, but that won’t survive a full page refresh. A number of techniques like local storage could be used, but there are always compatibility and browser-specific issues involved.
A proposed solution
I propose that each client can have an optional
Worth noting that:
I have a proof of concept with these changes added to API, along with a dead simple web app that displays a list of data when the user is signed in and a login form otherwise. With just a few lines of code, the user session is preserved in between page reloads for as long as the bearer token is valid.
In the extreme, this would mean that an application like Publish could be built without a backend, it could be as simple as a JS file kept in a centralised CDN that is included in a HTML page via a script tag, meaning that upgrading is as simple as changing the URL to point to a new version.
It also means that any other consumer app gets the same users, roles and permissions, enforcing consistency across the entire system.
Spec looks great!
Can we extend it to cover filtering too? Ideally we'd be able to apply filters to collections for specific users, such as only allowing the user to edit documents that have a particular field value.
Another useful extension would be to restrict editing of content that was created by the user.
Both of these concepts are currently required in client projects.