As part of my preparations to introduce web services, I've found that many web APIs provide two ways to authenticate: (a) a session cookie which can be obtained by "logging in", or (b) an "API key" ; either the API key or the session cookie is then provided with each request to the API, authenticating the request with the session and/or user. It should be noted that neither requests providing an API key nor those providing a session cookie contain further credentials.
For our (API) authentication, ideally, I'd like to be able to provide both the "api key" and the "session cookie" patterns for request authorization.
Additionally, I'd like session authentication to be available using:
- Username & password (preferably through CRAM-SHA2 or higher SHA)
* Note that in this scenario, the password validation could be anything; even a Kerberos or LDAP server
- WebAuth / FIDO2
- Client certificate
- (and more, if we come up with those)
== The Problem ==
Our current authentication setup requires plain text username and password on the initial login and each further request. We currently use basic auth to supply these values. In addition, we use a session cookie, but that only serves to validate the session. Thus every request currently requires the username, password and session cookie. The username and password are required because those are used to set up the database connection at the start of the request handling.
Most of the authentication systems above don't maintain a username/password combination visible to our server. By consequence, I'm looking for ways to eliminate the need for the username+password in the Web request. Also, if we'd want to use "API key" type authentication, that API key would need to hold in it (encrypted, but decryptable to the server) the username and password in order to be able to log into the database.
Note that the previous sentence explicitly states "in the Web request": ideally, LedgerSMB authentication can happen on two different levels -- the web request level and the database connection level. Basically, I'd like to start making the distinction between the web request authentication and the database authentication in such a way that our database authorization (access control) remains PostgreSQL-role-based (that is: doesn't change from the current model).
== The Proposal ==
My current idea is to separate the web authentication from the database authentication. The web application would use a generic user to set up the database connection, switching the session authorization to the role associated with the user, as if the user had logged in directly on the database. Technically, this is achieved by the Pg command 'SET SESSION AUTHORIZATION = username'. This means that once the session has been verified (either through the API key provided or the session cookie), authorization can be switched to the (web)authenticating user and regular processing (as we know it today) can continue.
This solution using the session authorization is very similar to what the Graphile (graphile.org
) project uses [they use SET ROLE instead of SET SESSION AUTHORIZATION -- there are subtle differences between their approach and my proposal].
The solution has the benefit of supporting direct connections to the database as they are today with all methods built into PostgreSQL, adding into the mix a second set of authorization options better suited to a web authentication scenario.
== The Request ==
Please comment on the above to get a good common understanding of what I'm describing and the best possible implementation at that.
Robust and Flexible. No vendor lock-in.