Introduction / FirstSpirit Server configuration / Authentication with OpenID Connect

Authentication with OpenID Connect

General information about OpenID Connect

Table of contents

What is OpenID Connect?

OpenID Connect (OIDC) is an authentication protocol built on OAuth 2.0. It enables clients to verify the identity of a user based on authentication by an authorization server (OpenID provider). Additionally, basic profile information of the user can be requested.

Term

Description

OpenID Provider (OP)

The authentication server that manages user identity (i.e., Keycloak).

Relying Party (RP)

The application that requests authentication; here: the FirstSpirit Server.

ID Token

A JSON Web Token (JWT) that contains the identity of the authenticated user.

Access Token

A token that enables access to protected resources (e.g., the UserInfo endpoint).

UserInfo Endpoint

An OIDC endpoint that provides additional user information (claims).

Claims

Key-value pairs with user information (e.g., preferred_username, email, groups)

  

The FirstSpirit OIDC Login Module supports three OAuth 2.0 / OpenID Connect flows:

Module description

Functionality and architecture

The FirstSpirit OIDC Login Module is a JAAS-based authentication module that is installed as a FirstSpirit module (FSM). It integrates into the standard JAAS login mechanism of FirstSpirit and delegates authentication to an external OpenID Connect provider.

Supported authentication flows

Authorization Code Flow (Browser Login / SSO)

The Authorization Code Flow is used for browser-based login via the ContentCreator or other web clients. The process is as follows:

  1. The user opens the FirstSpirit client in the browser.
  2. The LoginModule redirects the browser to the login form of the OpenID provider.
  3. After successful authentication, the provider redirects the browser back to FirstSpirit with an authorization code.
  4. The module exchanges the authorization code for an ID token and an access token.
  5. The module validates the ID token and optionally retrieves the user info from the endpoint.
  6. The user is logged into FirstSpirit.

This flow supports Single Sign-On (SSO); i.e., if the user is already logged in at the OpenID provider, authentication occurs without re-entering a password.

Resource Owner Password Credentials Flow (CLI/API)

The Password Flow is used for non-interactive clients, e.g., API access. The process is as follows:

  1. The client sends the username and password to FirstSpirit.
  2. The login module sends the credentials directly to the token endpoint of the OpenID provider.
  3. The provider responds with an ID token and an access token.
  4. The module validates the ID token and optionally calls the UserInfo endpoint.
  5. The user is logged in to FirstSpirit.

Important Not all OpenID providers support the Password Flow. Check your provider's documentation.

Token Exchange Flow (Token-based Authentication)

The token exchange flow enables authentication with an already existing token. This is useful when an upstream application already has a valid token. The process is as follows:

  1. The client submits an existing token (Access Token, ID Token, or Refresh Token) to FirstSpirit.
  2. The login module exchanges this token at the OpenID provider's token endpoint for a new ID Token and Access Token (RFC 8693 Token Exchange).
  3. The module validates the new ID Token and optionally calls the UserInfo endpoint.
  4. The user is logged into FirstSpirit.

Supported token types:

Token Type

Description

Access Token (standard)

Bearer Access Token - used when no type is specified.

ID

ID Token

refresh

Refresh Token

  
Important Not all identity providers support all token types. For example, Keycloak only supports access tokens.

Establishing an FS connection with a token

A FirstSpirit connection can be established using an existing token via the connection parameters:

import de.espirit.firstspirit.access.*;

// Connection with Access Token (default)
Connection c = ConnectionManager.getConnection(
    "localhost", 4088, ConnectionManager.SOCKET_MODE,
    "plain", Map.of("token", "abc123...")
);
c.connect();

// With explicit token type:
Map.of("token", "abc123...", "tokenType", "refresh")
Map.of("token", "abc123...", "tokenType", "ID")

Requirements

The following requirements are necessary for setting up the OIDC login module:

  • FirstSpirit Server from version 5.2.250606 with JAAS support
  • Registered OpenID Connect Provider (Issuer), here Keycloak
  • Client registration with the provider:
    • Client ID
    • Client Secret (recommended)
    • Configured redirect URI (for the authorization code flow)
  • Network access from the FirstSpirit server to the OpenID provider (HTTPS)

Client registration with the provider

Register a new client application with your OpenID provider using the following settings:

Einstellung

Wert

Client Type

Confidential (with Client Secret)

Redirect URI

The URL of the FirstSpirit server, e.g. https://firstspirit.example.com/fs5/auth

Grant Types

authorization_code (for browser login); optional: password (for CLI/API)

Scopes

openid, profile, email; optional: phone, groups

  
Important The exact procedure depends on the OpenID provider used.

Module installation and setup

Installing the FSM file

  • Open the ServerManager and connect to the FirstSpirit server.

  • Navigate to Server Properties > Modules.
  • Click on Install and select the file fs-oidc-login-{version}.fsm.
  • Confirm the installation.

WebApp Deployment (for Authorization Code Flow)

If you want to use the Authorization Code Flow, the web component of the module must be added to the root web app:

  • Navigate in the Server Manager to Project Properties > Web Components.
  • Add the web component of the OIDC module to the Root WebApp.
  • Redeploy the Root WebApp.

Without this step, the HTTP callback endpoint for the authorization code flow is not available.

Start OIDC service

Once you have installed the module, start the service OIDC Service:

  • In the Server Manager navigate to Server Properties > Modules > fs-oidc-login > OIDC Service.
  • Start the service using the Start button or enable Automatic start.

The service provides the configuration interface and is required by the login modules.

Editing configuration file (ServerManager GUI)

  • Double-click on the OIDC Service to open the configuration interface.
  • The configuration file fs-oidc.conf will be displayed in a text editor.
  • Adjust the configuration according to your OpenID provider.
  • Click OK to save the configuration.

Using the Upload button, you can add additional files (e.g., static provider metadata) to the configuration directory.

The configuration file is saved in the directory {FS-Install}/conf/fs-oidc/fs-oidc.conf.

Adjusting the JAAS configuration

Adjust the JAAS configuration file fs-jaas.conf. The default path is {FS-Install}/conf/fs-jaas.conf.

More information about JAAS configuration can be found here.

Configuration file (fs-oidc.conf)

You can configure the OIDC login module via the file fs-oidc.conf located in the directory {FS-Install}/conf/fs-oidc/. The file uses an INI-like format with sections.

Structure and sections

The configuration file supports multiple sections. Each section is introduced by [section name]. The [default] section is the default and serves as a fallback: if a value is not found in a specific section, the value from [default] is automatically used.

Which section of a login module is used is determined in the JAAS configuration file fs-jaas.conf via the option section (for more information see JAAS configuration).

Example structure:

[default]  
# Common configuration for all flows  
op.issuer=https://idp.example.com/realms/myrealm  
rp.clientId=firstspirit  
rp.clientSecret=secret123  
import.user=true  
user.login=${oidc:preferred_username}  
  
[auth]  
# Specific configuration for the Authorization Code Flow  
rp.redirectUri=${request:PROXY}  
  
[pass]  
# Specific configuration for the Password Flow  
op.scopes=openid, profile, email

In this example, [auth] and [pass] inherit all values from [default], but override individual properties for their respective use cases.

OpenID provider configuration (op.*)

Property

Description

Default

op.issuer

Mandatory. Issuer URL of the OpenID Provider, used both for validation and automatic metadata discovery.

(empty)

op.metadata

Optional filename or URL for static provider metadata in JSON format. If the value starts with "http:" or "https:", it is treated as a URL; otherwise, a file in the configuration directory is expected. If empty, automatic discovery via {issuer}/.well-known/openid-configuration is used.

(empty)

op.metadata.cacheTime

Cache duration for provider metadata in seconds. If empty, the cache duration is determined from the HTTP response headers (for more information see here).

(empty)

op.scopes

Comma-separated list of OAuth scopes to request; scopes not supported by the provider are automatically removed.

openid, profile, email, phone, groups

   

Relying party configuration (rp.*)

Property

Description

Default

rp.clientId

Required. The client ID that is registered with the OpenID provider.

(empty)

rp.clientSecret

The client secret for authentication at the token endpoint. If empty, no client authentication is performed. The authentication method (client_secret_basic or client_secret_post) is chosen automatically based on the provider metadata.

(empty)

rp.redirectUri

The redirect URI for the authorization code flow must match the redirect URI configured at the provider. Supports variable substitution (see here).

${request:URI}

   

User import configuration (import.*, user.*)

Property

Description

Default

import.user

If true, the user is created or updated in FirstSpirit at every login.
If false, it only checks ifwhether a FirstSpirit user with the mapped login name exists.

true

user.login

Mandatory. Mapping for the FirstSpirit login name.

${oidc:preferred_username}

user.email

Mapping for the user's email address.

${oidc:email}

user.phone

Mapping for the user's phone number.

${oidc:phone_number}

user.abbreviation

Mapping for the user's abbreviation.

${oidc:preferred_username}

user.realname

Mapping for the user's display name.

${oidc:name}

user.groups

Comma-separated list of user groups, typically mapped via the OIDC claim groups.

${oidc:groups}

user.section

Additional section information for the user.

${oidc:sub} ${oidc:exp}

   

Behavior during user import (import.user=true)

  • Users are marked as external.
  • The password of non-administrator users is set to an empty string (login only possible via OIDC).
  • The password of the administrator user (Admin) is not changed, so that local login remains possible.
  • User properties (name, email, groups, etc.) are updated at every login.

Group mapping (group.*)

Property

Description

Default

group.match.mode

Match mode for external group names.
Possible values: contains (the external group name must be contained in the FS group name) or equals (exact match).

contains

group.name

Mapping for the external group name.
Allows adding a prefix or suffix. The variable ${oidc:groupName} contains the current group name from the user.groups list.

${oidc:groupName}

   

Variable substitution

Configuration values in fs-oidc.conf support variable substitution. Variables have the syntax ${namespace:name} and are resolved at runtime.

OIDC-claims (${oidc:*})

OIDC variables are populated from the claims of the ID token and the UserInfo response. UserInfo claims take precedence over JWT claims, meaning that if a claim is present both in the ID token and in the UserInfo response, the value from the UserInfo response is used.

Standard JWT variables

Variable

Description

${oidc:Subject}

JWT Subject (sub): unique user ID at the provider

${oidc:Issuer}

JWT Issuer (iss): URL of the issuing provider

${oidc:Audience}

JWT Audience (aud): recipient of the token (client ID)

${oidc:JwtId}

JWT ID (jti): unique token ID

${oidc:IssuedAt}

Token issuance time (ISO-8601 format)

${oidc:Expiration}

Token expiration time (ISO-8601 format)

  

OIDC standard claims

All OIDC Standard Claims and JWT Registered Claims can be referenced via ${oidc:claimName}.

Commonly used claims:

Variable

Description

${oidc:preferred_username}

Preferred username

${oidc:name}

Full name

${oidc:given_name}

First name

${oidc:family_name}

Last name

${oidc:email}

Email address

${oidc:phone_number}

Phone number

${oidc:groups}

Group memberships (provider-dependent)

${oidc:sub}

Subject Identifier (identical to ${oidc:Subject})

  

Special variable for group mapping

Variable

Description

${oidc:groupName}

The current group name during the processing of the user.groups list. Usable only within group.name.

  
Important If a variable cannot be resolved, it will be replaced by an empty string and a warning will be logged.

FirstSpirit properties (${fs:*})

You can reference FirstSpirit server properties using ${fs:propertyName}. The value is read from the server configuration (fs-server.conf).

Example:

rp.redirectUri=https://${fs:SYMBOLIC_HOSTNAME}/fs5/auth

→ Reads the value of the server property SYMBOLIC_HOSTNAME from the FirstSpirit server configuration.

HTTP request variables (${request:*})

These variables are only available in the Authorization Code Flow as it involves an HTTP request.

Variable

Description

${request:URI}

The current HTTP request URL including the protocol, hostname, port, and path (excluding query parameters).

${request:PROXY}

Like ${request:URI}, but also considers the X-Forwarded-* headers of a preceding reverse proxy. The evaluated headers are: X-Forwarded-Proto, X-Forwarded-Host, and X-Forwarded-Port.

${request:FORWARDED}

Like ${request:URI}, but considers the RFC 7239 Forwarded header of a preceding reverse proxy; for example: Forwarded: proto=https;host=external.example.com.

  

Recommendation for reverse proxy setups

Use ${request:PROXY} or ${request:FORWARDED} for rp.redirectUri so that the redirect URI contains the external (public) URL of the server:

# For reserver proxys with X-Forwarded Headern:
rp.redirectUri=${request:PROXY}

# For reverse proxys with RFC 7239 Forwarded Header:
rp.redirectUri=${request:FORWARDED}

Standard ports (80 for HTTP, 443 for HTTPS) are automatically omitted in the generated URL.

Provider metadata and caching

The module requires the metadata of the OpenID provider (endpoints, supported algorithms, scopes, etc.). These can be provided in three ways.

Auto-discovery

If op.metadata is empty, automatic discovery is used. The module retrieves the standard URL {op.issuer}/.well-known/openid-configuration.

Important This is the recommended method because the metadata is always up to date.

Static metadata (file or URL)

Alternatively, op.metadata can be set via:

  • File: A filename (without path) in the configuration directory {FS-Install}/conf/fs-oidc/. The file must contain the JSON format of the OpenID Provider Metadata. Files can be uploaded via the Upload button in the ServerManager GUI.
  • URL: A URL that starts with http: or https:. The module retrieves the metadata from this URL.

# File in the configuration directory:  
op.metadata=provider-metadata.json  

# URL:  
op.metadata=https://idp.example.com/.well-known/openid-configuration

Cache configuration

Provider metadata is cached to avoid repeated HTTP requests. The cache duration is determined in the following priority:

  • Configuration value: op.metadata.cacheTime in seconds (if set)
  • HTTP Cache-Control Header: max-age directive from the HTTP response
  • HTTP Expires Header: expiration time from the HTTP response
  • No Caching: if none of the above information is available

For static metadata from a file, the default cache duration is 10 minutes.

Example:

# Caching metadaten for 1 hour: 
op.metadata.cacheTime=3600

JAAS configuration

The login modules are configured in the JAAS configuration file fs-jaas.conf (default path: {FS-Install}/conf/fs-jaas.conf). Each login module is registered with its fully qualified class name and a control flag.

Authorization Code Flow

fs5 { 
com.crownpeak.firstspirit.auth.oidc.OidcAuthLoginModule sufficient;
};

This login module can only be used for browser-based clients that support HTTP redirects.

Since the module performs an HTTP redirect to the IdP, it should always be placed last in the respective JAAS configuration with the value sufficient. This restriction does not apply to the other login flows.

Password Flow

fs5 { 
com.crownpeak.firstspirit.auth.oidc.OidcPassLoginModule sufficient;
};

This login module is used for SiteArchitect, ServerManager, and CLI access (fs-cli).

Token Exchange Flow

fs5 { 
com.crownpeak.firstspirit.auth.oidc.OidcTokenLoginModule sufficient;
};

Combining multiple flows

Multiple login modules can be combined to support different client types. The modules are called in the specified order, and the control flag sufficient causes processing to stop upon successful authentication by a module.

fs5 { 
com.crownpeak.firstspirit.auth.oidc.OidcAuthLoginModule sufficient;
com.crownpeak.firstspirit.auth.oidc.OidcPassLoginModule sufficient;
};

Typical configuration with fallback to local authentication

fs5 { 
com.crownpeak.firstspirit.auth.oidc.OidcPassLoginModule sufficient;
de.espirit.firstspirit.server.authentication.FSUserLoginModule optional; }
;

websso {
de.espirit.firstspirit.server.authentication.FSTicketLoginModule sufficient;
de.espirit.firstspirit.server.authentication.FSUserLoginModule optional;
com.crownpeak.firstspirit.auth.oidc.OidcAuthLoginModule sufficient;
};

In block fs5, the password flow (CLI/API) is attempted first, followed by the local FirstSpirit login. The websso block is used for browser-based clients: first, an existing ticket is checked, then the local login, and finally, the auth code flow with a redirect to the IdP. This ensures that login with local FirstSpirit credentials (e.g., admin) remains possible.

Using sections

Via the option section, each login module can be referred to a specific section in the fs-oidc.conf. This allows the flows to be configured differently, even though they use the same configuration file.

fs5 { 
com.crownpeak.firstspirit.auth.oidc.OidcAuthLoginModule sufficient section="auth";
com.crownpeak.firstspirit.auth.oidc.OidcPassLoginModule sufficient section="pass";
};

In this example, the Auth Code Flow uses the [auth] section and the Password Flow uses the [pass] section from the fs-oidc.conf. Values that are not set in the respective section are taken from [default].

If no section is specified, the default section is used automatically.

Configuration example: Keycloak

Prerequisites in Keycloak

  1. Create a new client in your Keycloak realm.
  2. Set Client authentication to On (Confidential).
  3. Enable Standard flow (Authorization Code) and optionally Direct access grants (Password Flow).
  4. Add the redirect URI, e.g., https://firstspirit.example.com/*.
  5. Optional: Create a client scope groups with a mapper of type Group Membership that generates the groups claim.

Configuration

fs-oidc.conf

[default]
op.issuer=https://keycloak.example.com/realms/myrealm
op.scopes=openid, profile, email, phone, groups

rp.clientId=firstspirit
rp.clientSecret=IHR_CLIENT_SECRET

import.user=true
user.login=${oidc:preferred_username}
user.email=${oidc:email}
user.phone=${oidc:phone_number}
user.abbreviation=${oidc:preferred_username}
user.realname=${oidc:name}
user.groups=${oidc:groups}
user.section=${oidc:sub} ${oidc:exp}

group.match.mode=contains
group.name=${oidc:groupName}

[auth]
rp.redirectUri=${request:PROXY}

fs-jaas.conf

fs5 { 
com.crownpeak.firstspirit.auth.oidc.OidcPassLoginModule sufficient;
de.espirit.firstspirit.server.authentication.FSUserLoginModule optional;
};

websso {
de.espirit.firstspirit.server.authentication.FSTicketLoginModule sufficient;
de.espirit.firstspirit.server.authentication.FSUserLoginModule optional;
com.crownpeak.firstspirit.auth.oidc.OidcAuthLoginModule sufficient section="auth";
};

Detection and correction of errors

Failed login

Symptom

Possible cause

Solution

"Parameter not set: [...] rp.clientId"

Client ID not configured

Set rp.clientId in fs-oidc.conf

"Parameter not set: [...] op.issuer"

Issuer URL not configured

Set op.issuer in fs-oidc.conf

"Token request error 'invalid_client"

Incorrect client secret

Check rp.clientSecret

"Token request error 'invalid_grant"

Invalid credentials or expired code

Check credentials; for Auth Code Flow, verify Redirect URI

"Token request error 'unauthorized_client'"

Client not authorized for the used grant type

Check grant types in provider configuration

"ManagerProvider not available, OIDC login disabled."

OIDC service not started

Start service in ServerManager (see here)

"Error creating OIDC login module instance"

Module not installed correctly

Check FSM installation

   

Redirect URI Problems

Symptom

Possible Cause

Solution

"redirect_uri_mismatch" at provider

The redirect URI in fs-oidc.conf does not match the URI configured at the provider.

Match URIs exactly (protocol, host, port, path)

Redirect URI contains internal IP/hostname

Reverse proxy does not forward forwarding headers.

Use ${request:PROXY} or ${request:FORWARDED} and check proxy configuration

Empty redirect URI

No HTTP request is present in the Password Flow.

Set rp.redirectUri explicitly or use ${request:*} variables only in Auth Code Flow

   

Token validation error

Symptom

Possible Cause

Solution

"Unexpected issuer"

Issuer in the token does not match op.issuer.

op.issuer must exactly match the issuer in the provider metadata.

"JWSAlgorithm not found"

The token's signature algorithm is not advertised by the provider in the metadata.

Check provider configuration

"Invalid Auth state"

The state parameter of the authentication response is unknown or has expired (timeout: 10 minutes)

Retry login; if network is slow, check for possible causes.

   

Logging and debug output

The module uses the FirstSpirit logging framework. To enable detailed debug output, activate debug logging for the following packages:

  • com.crownpeak.firstspirit.auth.oidc: Login module and configuration
  • com.crownpeak.firstspirit.auth.oidc.impl: Flow implementations
  • com.crownpeak.firstspirit.auth.oidc.nimbus: OIDC/OAuth operations (token requests, metadata, validation)

In debug mode, the following items, among others, are shown:

  • Provider metadata (endpoints, supported algorithms)
  • Authentication request URLs
  • JOSE header and JWT claims of the ID token
  • UserInfo responses
  • Warnings for unknown or missing claims or variables

Important Debug logging can output sensitive data (tokens, claims) in the logs. Enable it only temporarily for troubleshooting and then disable it.

© 2005 - 2026 Crownpeak Technology GmbH | All rights reserved. | FirstSpirit 2026.4 | Data privacy