Getting started

1. Add the starter

<dependency>
    <groupId>org.alexmond</groupId>
    <artifactId>uniauth-spring-boot-starter</artifactId>
    <version>4.1.0.3</version>
</dependency>

Nothing is enabled by default beyond the chain itself, because a starter that invented accounts would be worse than one that does nothing. Switch on at least one mechanism.

2. The smallest thing that works

uniauth:
  enabled: true          (1)
  internal:
    enabled: true
    users:
      - username: alice
        password: "{noop}s3cret"     (2)
        roles: [ USER, ADMIN ]
1 Required. The starter installs nothing until asked — it decides authorization, so being on the classpath is not consent.
2 {noop} is a DelegatingPasswordEncoder prefix meaning "stored in clear". Fine for a first run; use {bcrypt}$2a$10$… anywhere else, and inject it from the environment rather than committing it.

Start the application and everything but the login page needs a session. Sign in at /login.

3. Opening up some pages

uniauth:
  public-paths:
    - /
    - /about
    - /css/**

The starter already permits its own login page, the providers endpoint, /error and — when the approval gate is on — the pending page. Anything else you want reachable without a session goes here.

On Kubernetes, remember /actuator/**. Probes, Prometheus and Spring Boot Admin send no credentials, so requiring authentication there rejects exactly the callers the endpoints exist for.

4. Adding a directory

The LDAP jars are an optional dependency, so add them alongside the starter:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-ldap</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.security</groupId>
    <artifactId>spring-security-ldap</artifactId>
</dependency>

They are optional rather than transitive because carrying them is not free: their presence activates Boot’s own LdapAutoConfiguration, which builds a context source for ldap://localhost:389 and whose health indicator then reports DOWN. An application that never wanted a directory would fail its readiness probe, and no uniauth.* property can switch that off — the indicator is Boot’s, and it keys off the jar.

uniauth:
  ldap:
    enabled: true
    url: ldap://directory.example.com:389/dc=example,dc=com
    user-dn-patterns:
      - uid={0},ou=people
    group-search-base: ou=groups
    manager-dn: cn=admin,dc=example,dc=com       (1)
    manager-password: ${LDAP_MANAGER_PASSWORD}
1 Needed more often than it looks. A real directory is not world-readable — OpenLDAP’s default ACL is by self read … by * none — and a denied search answers no such object (32) rather than admitting the entry exists. Without a bind account the user authenticates and then arrives with no groups, and the error points at a missing entry that is plainly there.

The internal store and LDAP share one username/password form. They are told apart by the AuthenticationProvider chain, which is what lets a couple of local break-glass accounts sit beside a directory.

5. Adding an OIDC provider

UniAuth does not re-declare OAuth2 configuration. Use Spring Boot’s own properties:

spring:
  security:
    oauth2:
      client:
        registration:
          google:
            client-id: ${GOOGLE_CLIENT_ID}
            client-secret: ${GOOGLE_CLIENT_SECRET}
uniauth:
  oauth2:
    enabled: true    # the default

That is the whole integration. The endpoints, scopes and user-name attribute come from Boot’s CommonOAuth2Provider, keyed on the registration id; the chooser, the brand and the OIDC-versus-plain-OAuth2 detection all follow. See Provider recipes for the per-provider details that actually bite.

6. Adding SAML 2.0

SAML is an optional dependency, and it asks more of a build than the others — which is exactly why it is not transitive. Add both the starter and the Shibboleth repository:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security-saml2</artifactId>
</dependency>
<repositories>
    <repository>
        <id>shibboleth</id>
        <url>https://build.shibboleth.net/maven/releases/</url>
    </repository>
</repositories>

OpenSAML, which spring-security-saml2-service-provider needs, is not published to Maven Central, so a Central-only build fails to resolve org.opensaml:*. Carrying it transitively would push that repository onto every consumer of an authentication library, including the ones that will never speak SAML and have nothing in the error message to tell them why.

It has to be Boot’s SAML starter, not spring-security-saml2-service-provider alone. Boot 4 moved SAML autoconfiguration into its own module; the Spring Security artifact gives you the filters with no property binding, so spring.security.saml2.relyingparty.* is read by nobody, no repository is built, the chooser lists nothing, and saml2Login never installs — silently, because as far as the classpath is concerned nothing is missing.

uniauth:
  saml:
    enabled: true    # the default

Registrations themselves come from spring.security.saml2.relyingparty.registration.*, exactly as Boot documents them.

7. What to reach for next

  • The approval gate, if the answer to "may this person in" is not simply "yes, they authenticated".

  • Configuration, for the full property surface.

  • Examples, for a running demo of all four mechanisms at once.