Haiku Depot Server - SSO and Web UI
Terminology
- SSO - A user-management and authentication system that is intended to be used across all Haiku networked systems.
- Keycloak - The software project that delivers an off-the-shelf SSO solution. Haiku use this for their SSO.
- SPA - A “single page” application which operates in a single browser web page. The application is largely written in JavaScript or a different language transpiled to JavaScript and typically uses templating and UI logic that executes in the browser. This class of application communicates back to a backend using an API. HDS’s current UI is an SPA.
- AngularJS - A JavaScript framework for writing SPA applications.
- SSR - An application where more of the logic and state of the application exists on a server rather than on the client.
- Spring - A framework for writing Java server applications.
- SpringMVC - A framework under the Spring umbrellar that, when combined with a templating system, is able to generate web interfaces from a Java server application.
- JTE - A library and approach for templating HTML and other textual output in a Java server application.
- Thymeleaf - A library and approach for templating HTML and other textual output in a Java server application.
Background
Back in 2013 when the Haiku Depot Server project started, the Haiku project didn’t have an SSO option deployed so, I created a home-grown user management system within HDS itself. Not long after HDS was in production, the Haiku admin team deployed KeyCloak identity platform (SSO) so that Haiku community users could use the various online services with one login and identity. Despite being desirable to integrate HDS with the new Haiku SSO, it was – and still is – more challenging than it looks to unwind the home-grown login system. Ideally though, HDS would no longer manage users and would instead delegate this responsibility to the SSO.
The web user interface for HDS was build back then with the AngularJS framework. The AngularJS technology was advanced for the early 2010s, but by the mid 2010s was dropped in favor of Angular framework. Don’t be fooled by the similar name; getting from AngularJS to Angular, in practical terms, meant a re-write. For this reason, given limited resources, HDS has stuck with AngularJS which hasn’t been a bad decision because has been working well all this time. The problem is that it’s been unsupported for some years and is not trivial to learn.
This article is about a plan to introduce SSO integration and, at the same time, replace the AngularJS web UI in a combined strategy.
Goals
Understanding what the objective is, helps to gain clarity about the undertaking; especially when time is limited and, it’s likely to be drawn out.
SSO Goals
- Users authenticate with the SSO to access HDS web UI
- HDS has no user management facility and instead delegates these functions to the SSO
- Users authenticate with the SSO in the Haiku Depot desktop application and then use tokens to authenticate with HDS
- Haiku Depot desktop UI has no signup or user-creation UI functions and instead delegates these functions to the SSO
- The maintenance surface area related to authentication for HDS and the Haiku Depot software is reduced
Web UI Goals
- Technology choices are centric around long-term maintenance, longevity, reducing tech surface area, easy on-boarding and low-cognitive load
- The UI transitions from the discontinued AngularJS-centric technology to a server-side rendered (SSR) web UI using Java
- The UI transitions from a stateless technology to a stateful server-side session architecture
- Standard HTML and CSS technology are used with JavaScript in a limited way where necessary
- No JavaScript libraries are used and no JavaScript ecosystem is tracked
- Targets a lowest-common-denominator browser and is lightweight on the client browser
- Target browsers are assumed to support SVG images and icons
- Common non-admin functions are usable on mobile and desktop
- Built-in browser navigation techniques such as history and back-button are leveraged rather than in-page application state
- Supports multi-language localization
- Conservatively reflects the look and feel of the default Haiku aesthetic
- Does not support customizations
Approach with Limited Resources
Although hopefully not unattractive, the UI that will result from this effort is unlikely to be highly polished at first. In the first instance, effort will be directed into the achieving the technical goals above. Developer resources are likely to be limited, and it may take some time to achieve. Once the goals are achieved then it will be possible to look at refinement. This might not be universally appreciated.
Strategy
Starting state
Before the project starts, the system has the following architectural structure;
As well as the single page application (SPA) written with AngularJS technology, HDS also supports a server side rendered (SSR) interface as well. This was built in early 2010s to support browsers that did not have an advanced JavaScript interpreter. For this reason, the SSR interface is currently called a “simplified interface”. Internally this is called the “multi-page” interface.

This SSR interface uses SpringMVC within the backend and currently uses Thymeleaf templating.
Phase 1
After phase 1, the system has the following architectural form with changes highlighted in red;
Thymeleaf is somewhat complex and functions through dynamic interpretation with no build-time type safety. A newer SSR page-render technology called Java Template Engine (JTE) is available with a less complex syntax and using a compile-time approach providing type-safety. There also exists a plugin for JTE that works with the Intelli-J IDE which speeds up development.
This phase would see the existing SSR interface switch from Thymeleaf to JTE. The current limited “simplified interface” functionality will be extended slowly to cover the entire application’s functions. The JTE, CSS, JavaScript and localization infrastrucure setup would be part of this phase.
New SpringMVC controllers will be created for the SSR that use the HDS external RPC-API interfaces. This will be faster to implement because the API logic is already tuned to support the existing UI functionality. In the future, should the JTE templating library be no longer viable, the same controllers should be able to be used with a different templating library.
The very first release will be knowingly unlocalized. It may be prudent to wait for any issues with the new UI to settle before investing in localization although, it could, in theory start at this point. The localization will be re-started in a new file in the HDS application server. The new file is multipagemessages_<language-id>.properties and will need to be setup in Polygot. I recognize that restarting the localization from scratch will be a larger job for the translators but, I can see doing otherwise (have tried) is going to be difficult. With the new SSR technology, the full Java built-in message localization system is used which means that proper language-specific pluralization is now possible.
As I can read German, it would be helpful to maintain parity between German and English to help with catching any cases where the new UI elements are not localizable; hopefully Humdinger can still help out with this!
It would be possible for a parallel flow to occur at this point to implement all the remaining “logged out” pages. See phase 4 for a list of these. It would also be possible to carry on with any styling improvements of the pages.
Phase 2
After this phase, the system has the following form with changes highlighted in red;
In this phase, the system will implement Spring Session using the Postgres database as a means of persisting the sessions. Other storage mechanisms could be used such as Redis but this would make the HDS deployment more complex with additional elements to deploy.
Only authenticated users will obtain a session. The session will be tracked using a browser cookie. Logged-out users will remain stateless. Authentication will progress through a new SSR page and, in this phase, will use the existing legacy user management system.
The SPA will switch from being stateless over to using the same cookie-based session; it will stop sending JWT tokens back to HDS to identity the user and will instead rely on the browser cookies. The SPA will use the new SSR page and SpringMVC controller for authentication, redirecting back to the SPA once authentication succeeds.
The same session system will support the legacy SPA and SSR UIs and will simply carry an HDS authentication token.
A new endpoint will be provided to support logout.
The user usage agreement will need to be updated to explain the changes because browser cookies will be used to track sessions.
The HaikuDepot desktop application will remain as-is for this phase and will continue to use the existing authentication mechanics.
Phase 3
After this phase, the system has the following form with changes highlighted in red;
This phase is a significant transition that is “big bang” in nature where a smooth rollback will be challenging.
Keycloak
Two new KeyCloak clients will be required. One client will need to be configured for HDS and another for the Haiku Depot desktop application. The HDS one will use code-flow. The Haiku Depot desktop application one will use device-flow. Instructions for setting up a development instance of KeyCloak will need to be written. The instructions will need to include configuration guidance for attaining an analogous setup to the Haiku SSO system.
The KeyCloak access token will need to carry a JWT structure.
HDS
The user table in the HDS database will gain another string column sso_identifier which will carry the SSO user identifier which, in the case of KeyCloak, is a UUID. This field will be NOT NULL.
At the time of writing, there’s approximately 40 users who are connected to data in the system.
SELECT COUNT(DISTINCT u.id)
FROM haikudepot.user u
WHERE (1 = 0
OR EXISTS (SELECT pup1.id FROM haikudepot.permission_user_pkg pup1 WHERE pup1.user_id = u.id)
OR EXISTS (SELECT psm1.id FROM haikudepot.pkg_supplement_modification psm1 WHERE psm1.user_id = u.id)
OR EXISTS (SELECT ur1.id FROM haikudepot.user_rating ur1 WHERE ur1.user_id = u.id)
OR u.is_root = true
OR u.
)
AND u.active = true;
This limited group of users will have their user record manually linked to their SSO identifier. Remaining users will be deleted as they will effectively serve no purpose after SSO is integrated.
The authentications will start at HDS but will no longer progress through the HDS user management system. Instead, users will be directed to the Haiku SSO service to authenticate using Open-ID protocol. The Haiku SSO service will redirect the user back to the HDS web UI.
On re-entry to HDS, if absent, a user record in the HDS database will be created and linked to the SSO identifier along with the nickname and email. If the user already exists then the nickname and email will be updated. The email is only copied so that later, the HDS system is able to contact the user for some administrative purpose if necessary. These fields are correlated on every authentication.
The session carries the SSO user data. No other additional structure is necessary in this phase.
There exists APIs and SPA UI in the HDS system for servicing user authentication, creation and editing. The APIs in this area should be marked as deprecated and should return errors. The UI should be removed and also removed from any navigation paths. The Captcha system within HDS can also be removed.
HDS will continue to accept OpenID access tokens to authenticate individual requests. This would be used from the HaikuDepot desktop application for example. The sub claim on the access token will provide a mechanism to query for a corresponding user record. At the scale HDS is running at, an eventually-consistent in-memory cache of the user record should be sufficient to not cause any major latency.
The OpenID integration supplied by Spring Security is intended to be used to provide the basis for integration with the SSO; hopefully mostly out of the box. HDS already uses Spring Security so this should be a natural extension.
HDS Config Changes
The Spring Security configuration for OpenID will be required. These configuration properties are prefixed with spring.security.oauth2.client.registration.keycloak.
Existing configuration properties prefixed with hds.authentication should be removed from the build-product. Immediately after deployment env-vars should be removed from the K8S Deployment configuration with prefix HDS_AUTHENTICATION.
The API MiscellaneousApiService#getRuntimeInformation should be updated to return false for allowsNicknamePasswordAuthentication which will stop the older HaikuDepot desktop application from supporting legacy authentications. Additionally, this API will supply the information necessary for the desktop application to integrate with SSO; for example the KeyCloak base URL, a URL for sign-up and the client ID.
Immediately after deployment, env-vars should be removed from the K8S Deployment configuration with prefix HDS_AUTHENTICATION.
The user usage conditions should be updated at this time to cover the new arrangements.
HDS Testing
Significant work will need to be carried out so that the automated testing for HDS can proceed using the new SSO-based authentication mechanism. It’s currently unclear how this will work but a simulated SSO system could be used or Test-containers KeyCloak may also be an option.
Haiku Depot Desktop Application
The desktop application will likewise need some major changes that will have to be coupled with the changes above. The desktop application will drop its own authentication path and will instead use OpenID device-flow. The client logic for OpenID should be made re-usable within the application sources to allow for later re-use.
HDS will provide on the getRuntimeInformation API the SSO’s OpenID base URL, a client ID as well as a URL for signup. Using the base URL, the desktop application can use the well-known URL path to obtain the standard OpenID configuration data. For example;
https://sso.haiku-os.org/realms/haiku/.well-known/openid-configuration
The Haiku installation would ideally have a web browser to progress the device-flow authentication but, it would also be possible to display the URL or QR code for use on another device. The desktop application will poll the SSO system to detect the completed authentication; once it is completed, the desktop application is able to obtain an access token to use with HDS APIs and a renewal token to refresh the access token from the SSO when the access token expires.
An authentication representing a user who has never previously interacted with HDS will trigger HDS to create a new user database record and associate it with the SSO user.
These changes will be patched into master as well as the R1B6 branches. Much older Haiku Desktop installations will simply fail to authenticate because the APIs will error. Newer installations will detect the allowsNicknamePasswordAuthentication value queried at application start tim e from the getRuntimeInformation API and will hide the authentication options in the desktop application’s UI. Catering for older clients’ authentication is not worthwhile.
On the desktop application, a successful authentication with the SSO should delete any username / password credentials persisted to the local key-store (see IdentityAndAccessUtils.cpp). The OpenID access token and renewal token will be retained in-memory. The renewal token will be persisted to the key-store. On start, the desktop application will be able to communicate to the SSO server to acquire a new access token using the renewal token.
A logout from the desktop application will terminate the SSO session with the renewal token and the renewal token will be removed from the key-store.
The Haiku-native user authentication flow will be removed.

The Haiku-native create-user flow within the desktop application will be removed. When the user opts to create a new user, they will redirect to the SSO user signup interface. Given the amount of work involved, the extra effort of writing a Haiku-native user-signup interface for KeyCloak is not worthwhile; at least not in the first instance. It is also possible that the Haiku sys-admins may wish to introduce MFA or other authentication challenges such as email-verification; implementing a Haiku-native interface for those more complex interactions will be time-consuming and could become a blocker for administrative goals.

The desktop application’s version should be incremented to keep track of compatibility for disabling older clients incapable of OpenID authentication in the following years.
Phase 4
After this phase, the system has the following form;
Phase 4 is about completing the UI migration to the full server-side rendered UI and dropping the SPA UI.
The remainder of the logged out pages are to be completed first;
- List pkg versions for pkg
- List repositories
- View pkg changelog
- View pkg version localization
- View repository
- View repository source
- View repository source mirror
- View user rating
Unlike phase 1 where the pages were unauthenticated and largely search-and-display, most of the rest of the system is administration-related. Early on it wasn’t clear how frequently many admin operations would be required and, I’d implemented most admin workflows in SPA UI. It seems like the time investment to achieve this again with the new UI will be high but many of the admin operations are very infrequently activated. There is a ranking;
- Must have
- Add + edit user rating
- Edit pkg categories
- Edit pkg changelog
- Edit pkg icon
- Edit pkg localization - This was going to be outsourced to Polygot but has not been achieved to date.
- Edit pkg prominence
- Edit pkg screenshot
- List authorization pkg rules
- List jobs
- List users - HDS side representation
- Runtime information
- View job
- View user
- Add authorization pkg rule
- Should have
- Add + edit repository
- Add + edit repository source
- Add + edit repository source mirror
- Nice to have
- Pkg category coverage import spreadsheet
- Pkg feed builder
- Pkg icon archive import
- Pkg localization import
- Pkg screenshot archive import
Once the “must have” items are completed, it will be possible to drop or disable the SPI interface and slowly work on the remaining pages.
Phase 5
After this phase, the system has the following form with changes highlighted in red;
Phase 5 is about splitting the new SSR UI out from the main HDS application so that there is a true backend application server and a true frontend application server. This wasn’t possible to do from the offset because the SPI and the SSR UIs shared the same web session and, it would have been complex to maintain the two systems.
The advantage of this approach is that the backend exposes an API which is cleanly used by the frontend SSR application. This is akin to how the SPA application is currently working.
Other options considered
Other options and technology options considered;
- Continued use of AngularJS - it’s possible to continue to use AngularJS. It’s working today and the UI surface area of HDS is not meaningfully expanding. The downside here is that the technology has been moribund for many years and therefore enthusiasm for learning it is likely limited. I know it, but if somebody else has to pick it up then it’s unlikely to happen smoothly. If anything happens to make AngularJS unviable, then making a transition to something else in an orderly manner with very limited capacity will be difficult. This doesn’t seem like a great option.
- Build another SPA UI - A new SPA UI is also possible using technology such as React, VueJS or Svelt and would work well, but means me learning another SPA library for which time is limited and I would need to track an evolving SPA framework. In short, another SPA might be nice, but it’s likely to be a time-consuming approach with higher long-term maintenance cost. SSR technology with Java/Spring using simple HTML/CSS and lightweight JavaScript is aligned with existing HDS technology, would be faster to implement, reduces the technology surface area, has strong type-safety, will be lighter on the browser and owing to the relative readability, stability and continuity of the Java/Spring technology is likely to mean less maintenance overhead.
- Use a different technology for the SSR - it would be possible to use a different technology for the SSR frontend such as Python + Django or NodeJS for example. However, this would increase the technology and maintenance surface area of HDS for no meaningful gain. HDS is already running well on Java/Spring so fragmenting the technology space would at best be unhelpful.
- Stick with the home-grown user identity system - HDS’s own user authentication and identity system is stable and working fine. It would be possible to carry on employing this, but users wouldn’t be able to use their regular Haiku SSO credentials and identity with HDS and the user management functions such as “forgot password”, “create user”, “captcha” and so on would need to be re-built out in the new UI; a wasted effort since the SSO already provides these functions centrally. If we want to introduce MFA, email verification or other security technology then that would be a huge effort to do outside the SSO as well. Using SSO is a big transition, but brings significant benefits and coupled with the timing around the UI technology-refresh makes sense time-wise as well.
- Redirect the authentications to the SSO through HDS - in this approach, HDS would retain its authentication interfaces as-is and would re-use the SSO for the last mile authentication. This would be possible and might mean less change but would separate the HDS authentications from the other SSO authentications at the browser level, retain the need to rebuild the interfaces in the new UI and would also limit future options for implementing functions such as MFA. This approach is not making sense.
Summary and Considerations
The need to slowly replace the Web UI technology is clear. Combining this effort with moving to SSO seems like it will less work overall; or at least will be complimentary. The project looks to be quite large and may take a long time to complete however there is no rush. A practical approach will be taken to achieve the key goals and then refocus on time-consuming aesthetics later.