--- title: "Architecture of Qvisqve, an authorization server" author: QvarnLabs Ab date: work-in-progress ... # Introduction **What.** Qvisqve is an authorization server. At this stage, it is an [OAuth2][] authorization server, but later on it will grow into a provider for [OpenID Connect][]. Qvisqve controls access to a web API: the API client authenticates itself to Qvisqve, gets an access token from Qvisqve, and gives the access token to the API server. This de-couples the acts of authentication and authorization and resource access, which simplifies the individual software components. [OAuth2]: https://en.wikipedia.org/wiki/OAuth [OpenID Connect]: https://en.wikipedia.org/wiki/OpenID_Connect **Why.** Qvisqve is not the first server of its kind. We wrote Qvisqve because we wanted something we liked: * is fully free, open source software * has a simple, clear architecture and implementation * has a chance of being accepted into the Debian distribution * is simple and fast to install, and configure * is simple, transparent to operate * scales to many requests per second, many identities * is flexible and easily extensible, as far as authentication methods go * is robust and reliable * is stable **Web, not enterprise.** We operate in a "web environment, which is different from a typical enterprise or large organisation environment. We do not care about "single sign-on" across unrelated services, for example. **Why not an alternative.** We've used [Gluu][], but for our uses it is cumbersome, and not simple. [Gluu]: https://www.gluu.org/ **Usage driven development.** We develop Qvisqve mainly based on the needs of actual users, not to complete feature comparsion matrices. ## Glossary * access token * Qvarn: a program for storing structured data, especially personal data, and providing access control. See . # Current state **Currently, alpha level.** Qvisqve is an OAuth2 authorization server that supports the client credential grant only. This means only the API client authenticates itself to Qvisqve, but not the actual end-user. This is so that we can use Qvisqve with the [Qvarn][] server and have the Qvarn API tests pass. [Qvarn]: http://qvarn.org/ Further, the first development phase aims for a simplistic OAuth2 server. For example, the list of API clients will be hardcoded in the configuration file. This is acceptable to get development started, but soon after that we will add features such as dynamically registering clients. ## Vision for the future In the longer term, we aim for Qvisqve to be an OpenID provider using the OpenID Connect protocol. This includes being able to have the end-user authenticate and authorize use of resources. We will make it simple and flexible to provide authentication methods (such as username/password, client-side certificates, and U2F tokens). We will be replacing the static configuration file, with the list of clients, with Qvarn. Eventually, one goal is to make it possible to allow every person registered in Qvarn to authenticate with Qvisqve. Eventually, we aim to have Qvisqve certified as a compliant OpenID Connect implementation. We also intend to make Qvisqve be flexible, easy, and secure. # Known problems and things to solve later The main problem of Qvisqve at this stage is that it doesn't exist. All other problems can be derived from that. We don't have a good way of rotating the token signing keys. # Requirements For the first development phase of Qvisqve, our acceptance criteria are: * setting up a Qvisqve instance is simple: the software should be provided as a Debian package installable on Debian 9 (stretch), and a corresponding Ansible playbook that configures the instance * configuring a Qvarn instance to use the Qvisqve instance is simple: the Ansible playbook for Qvarn should be updated to work with Qvisqve instead of Gluu * the Qvarn API tests pass Once we have that working, we will add more requirements. ## Non-requirements At this stage, we do not care about speed, portability, or other such qualities. We care about security enough that we want to avoid any glaringly obvious security issues, but, for example, we don't care about storing API client secrets in an encrypted fashion. # Architecture overview Qvisqve provides an HTTP API interface for authentication. The only relevant endpoint is `/token` and to use it, the client must authenticate itself using its "client id" and "client secret" using HTTP Basic Authentication. A successful response will have the access token in its JSON body. A request: POST /token HTTP/1.1 Host: qvisqve.example.com Authorization: Basic c2FsYW1pOnBhc3N3b3Jk Content-Type: application/x-www-form-urlencoded grant_type=client_credentials?scope=version A successful response: HTTP/1.1 200 OK Content-Type: application/json { "access_token": "CAFEF00D", "token_type": "bearer", "expires_in": 3600, } The client should extract the access token (`CAFEF00D`) and add it to any requests it makes to the resource server: Authorization: Bearer CAFEF00D The client does not need to understand the token, it merely copies it into requests it makes. ## Components Qvisqve consists of several components @startuml title Qvisqve components component [API client] as client node "Qvisqve" { component [Haproxy] as haproxy component [backend] as backend component [configuration] as config } client -> haproxy : 2. https haproxy -> backend : 3. http backend <- config : 1. read at startup haproxy <- backend : 4. access token client <- haproxy : 5. access token @enduml **haproxy** is a load balancer. For Qvisqve we use it to provide TLS for communication with the client. The **backend** implements the actual Qvisqve HTTP endpoints and creates and returns access tokens to the client. The **configuration** lists the API clients (the id, the secret, and any scopes the client is allowed to have), as well as the RSA keys used to sign the access token. The API provider (Qvarn) will be configured to know the public RSA key so that it can verify that an access token has been created by Qvisqve. The client and haproxy use TLS. haproxy and the backend use plain HTTP, but they will be deployed in an environment where the plain text communication cannot be overheard, such as via the `localhost` interface (haproxy and backend would run on the same host).