This is the multi-page printable view of this section. Click here to print.

Return to the regular view of this page.

Setting up Stroom with an Open ID Connect IDP

How to set up Stroom to authenticate users: with its own internal identity provider, with a 3rd party one such as KeyCloak, Cognito or Google, or behind an authenticating proxy such as an AWS Application Load Balancer.

Stroom authenticates its users against an Identity Provider (IDP) Identity Provider (IDP) An Identity Provider is a system or service that can authenticate a user and assert their identity. Identity providers can support single sign on (SSO), which allows the user to sign in once to the Identity Provider so they are then authenticated to all systems using that IDP.Click to see more details... using Open ID Connect . There are three deployment models, distinguished by where the user accounts live and which component performs the sign in.

  • Internal IDP - Stroom acts as its own identity provider and manages the user accounts itself. This is the default.
  • External IDP - A 3rd party identity provider, such as KeyCloak, Cognito or Google, holds the accounts; Stroom performs the sign in by redirecting the browser to it.
  • Edge Proxy RP - A 3rd party identity provider holds the accounts, but an authenticating reverse proxy in front of Stroom performs the sign in (an AWS Application Load Balancer with Cognito, NGINX with oauth2-proxy, etc.) and passes Stroom a verified identity with each request.

Not sure which you have?

Your situation Model
No existing identity provider, or Stroom should manage its own accounts Internal IDP
An existing IDP (KeyCloak, Cognito, Google, Entra ID) and browsers reach Stroom directly, or through a proxy that only routes External IDP
A load balancer or proxy in front of Stroom signs users in before traffic reaches it, e.g. an ALB authenticate-cognito rule, oauth2-proxy, or a policy that unauthenticated traffic must not reach the application Edge Proxy RP

Whichever you use, authorisation is always handled by Stroom. The provider establishes who a user is; Stroom decides what they are allowed to do.

1 - Accounts vs Users

The distinction between Accounts and Users in Stroom.

In Stroom we have the concept of Users and Accounts, and it is important to understand the distinction.

Accounts

Accounts Account Refers to a user account in Stroom’s internal Identity Provider. An Account holds the credentials a person authenticates with, and exists only where Stroom is its own Identity Provider, unlike a User which exists in every deployment.Click to see more details... are user identities in the internal Identity Provider (IDP) Identity Provider (IDP) An Identity Provider is a system or service that can authenticate a user and assert their identity. Identity providers can support single sign on (SSO), which allows the user to sign in once to the Identity Provider so they are then authenticated to all systems using that IDP.Click to see more details.... The internal IDP is used when you want Stroom to manage all the authentication. The internal IDP is the default option and the simplest for test environments. Accounts are not applicable when using an external 3rd party IDP.

Accounts are managed in Stroom using the Manage Accounts screen, reached by selecting

Security
Manage Accounts

from the main menu. An administrator can create and manage user accounts allowing users to log in to Stroom. See User Accounts.

Accounts are for authentication only, and play no part in authorisation (permissions). A Stroom user account has a unique identity that will be associated with a Stroom User to link the two together.

When using a 3rd party IDP this screen is not available as all management of users with respect to authentication is done in the 3rd party IDP.

Accounts are stored in the account database table.

Stroom Users

A User User Refers to a Stroom User that is linked to either an Account in Stroom’s internal Identity Provider or a user account in an external Identity Provider. A Stroom User is primarily concerned with authorisation (i.e. application/document permissions and group memberships) rather than authentication, though disabling one also refuses that person at authentication and ends any access they currently hold.Click to see more details... in Stroom is used for managing authorisation, i.e. permissions and group memberships. Its one bearing on authentication is that a disabled User is refused at authentication, whichever Identity Provider (IDP) Identity Provider (IDP) An Identity Provider is a system or service that can authenticate a user and assert their identity. Identity providers can support single sign on (SSO), which allows the user to sign in once to the Identity Provider so they are then authenticated to all systems using that IDP.Click to see more details... is in use, and has their sessions and tokens withdrawn. See Users and Groups. A user has a unique identifier that is provided by the IDP (internal or 3rd party) to identify it. This ID is also the link it to the Stroom Account in the case of the internal IDP or the identity on a 3rd party IDP.

Stroom users and groups are managed in the stroom_user and stroom_user_group database tables respectively.

2 - Stroom's Internal IDP

Details about Stroom’s own internal identity provider and authentication mechanisms.

By default a new Stroom instance/cluster will use its own internal Identity Provider (IDP) Identity Provider (IDP) An Identity Provider is a system or service that can authenticate a user and assert their identity. Identity providers can support single sign on (SSO), which allows the user to sign in once to the Identity Provider so they are then authenticated to all systems using that IDP.Click to see more details... for authentication.

In this configuration, Stroom acts as its own Open ID Connect Identity Provider and manages both the user accounts for authentication and the user/group permissions, (see Accounts and Users).

A fresh install can create a user account called admin with the password admin, which is a member of a group Group (users) A named group of users to which application and document permissions can be assigned. Users can belong to multiple groups. A Group can belong to multiple groups. Groups allow permissions to be assigned to the group such that members of that group inherit those permissions.Click to see more details... called Administrators holding the Administrator application permission. This admin user can then be used to set up the other users on the system.

This bootstrap account is only created when stroom.security.identity.autoCreateAdminAccountOnBoot is set to true, which is not the default. The password is deliberately weak, and by default Stroom requires it to be changed at the first login, governed by stroom.security.identity.passwordPolicy.forcePasswordChangeOnFirstLogin.

Without that property, no account is created and nobody will be able to log in to a new installation. You must instead create the first administrator from the command line.

Additional user accounts are created and maintained using

Security
Manage Accounts

See User Accounts for managing those accounts, and Signing In for what users experience.

Configuration for the Internal IDP

While Stroom is pre-configured to use its internal IDP, this section describes the configuration required.

In Stroom:

  security:
    authentication:
      authenticationRequired: true
      openId:
        identityProviderType: INTERNAL_IDP

In Stroom-Proxy:

  feedStatus:
    apiKey: "AN_API_KEY_CREATED_IN_STROOM"
  security:
    authentication:
      openId:
        identityProviderType: NO_IDP

3 - External IDP

How to set up Stroom to use a 3rd party identity provider such as KeyCloak, Cognito or Google for authentication.

You may be running Stroom in an environment with an existing Identity Provider (IDP) Identity Provider (IDP) An Identity Provider is a system or service that can authenticate a user and assert their identity. Identity providers can support single sign on (SSO), which allows the user to sign in once to the Identity Provider so they are then authenticated to all systems using that IDP.Click to see more details... (KeyCloak, Cognito, Google, Active Directory, etc.) and want to use that for authenticating users. Stroom supports 3rd party IDPs that conform to the Open ID Connect specification.

This page describes what Stroom needs from any such provider. It applies whichever provider you use, so read it before following one of the provider specific pages.

What Stroom Needs from the Provider

Stroom is a confidential OAuth 2.0 client using the authorization code flow. To register it with a provider you need the following.

What Value
Client type Confidential, i.e. one that is issued a client secret. Stroom is a server side application and keeps its secret on the server.
Grant type / flow Authorization code. Stroom does not use the implicit or password flows.
Redirect URI https://STROOM_FQDN/api/auth/flow/v1/signin-oidc (see below)
Post logout redirect URI https://STROOM_FQDN/ (see below)
PKCE Supported, and may be required (see below)
Scopes openid and email by default

STROOM_FQDN is the public facing address of Stroom, which is what you have configured as appConfig.publicUri and is the address users type into their browser. If Stroom is behind a load balancer or Nginx, it is that address and not the address of an individual node.

The Redirect URI

The redirect URI, sometimes called the callback or reply URL, is where the provider sends the user’s browser once they have authenticated.

Stroom uses a single fixed redirect URI:

https://STROOM_FQDN/api/auth/flow/v1/signin-oidc

Register that exact value. It does not vary with the page the user was trying to reach, so there is no need to register a wildcard, and you should not do so. The page the user came from is remembered separately by Stroom and does not travel through the provider.

If Stroom is served under a path prefix, i.e. appConfig.publicUri.pathPrefix is set, that prefix comes before /api.

The Post Logout Redirect URI

When a user signs out, Stroom sends them to the provider’s logout endpoint and asks to be returned to Stroom’s public root:

https://STROOM_FQDN/

Stroom appends a state query parameter to that URI. Providers that match post logout redirect URIs exactly may need to be told to permit it, so if sign out leaves the user on an error page at the provider, that is the usual cause.

The name of the parameter Stroom uses to pass this URI is controlled by logoutRedirectParamName, which may be post_logout_redirect_uri, the default and current specification, or redirect_uri for older providers.

PKCE

Stroom always sends a PKCE code_challenge using the S256 method, and the matching code_verifier when it exchanges the authorization code for tokens.

There is nothing to configure in Stroom for this. Providers that require PKCE, and anything following OAuth 2.1, will be satisfied, and providers that do not support it ignore the extra parameters. Where the provider lets you insist on PKCE, as KeyCloak does, you can safely turn that on.

Claims

Stroom reads three things about a user from the token.

Setting Default Purpose
uniqueIdentityClaim sub Links the identity at the provider to a Stroom user. Must be unique at the provider and must never change for a given person.
userDisplayNameClaim preferred_username A friendlier name shown in the Stroom UI. Need not be unique and may change.
fullNameClaimTemplate ${name} Builds the user’s full name from claim values, e.g. '${given_name} ${family_name}'.

Not every provider issues preferred_username, so check the provider page before assuming the defaults will do.

Token Validation

Stroom validates every token it is given, whether that is the id_token from an interactive sign in or a bearer access token presented to the API.

The signature must verify against a key from the provider’s JWKS, and the algorithm must be one of the RSA, RSA-PSS or ECDSA families. Unsigned tokens and tokens signed with an HMAC algorithm are refused.

The issuer must match what the provider advertised, and the audience must match what Stroom expects. Audience validation is the part most likely to need attention, because providers differ in what they put in the aud claim of an access token. See Audience validation.

Users and Permissions

Authentication is handled by the provider. Authorisation, i.e. what a user may do once they are in, is always handled by Stroom.

Whenever a user successfully signs in via the provider, Stroom automatically creates an entry for them in its own user table. That user starts with no permissions and no group memberships, so an administrator must grant those. This does mean a new user has to sign in once before an administrator can do anything with them.

The very first administrator is a chicken and egg problem, since there is nobody able to grant permissions yet. That is solved with the manage_users command, described on each provider page.

3.1 - Stroom Configuration

A reference for every Stroom and Stroom-Proxy setting involved in authenticating against an external identity provider.

This page is the provider agnostic reference for the Stroom side of the configuration. The provider specific pages give the values to put in it for a given Identity Provider (IDP) Identity Provider (IDP) An Identity Provider is a system or service that can authenticate a user and assert their identity. Identity providers can support single sign on (SSO), which allows the user to sign in once to the Identity Provider so they are then authenticated to all systems using that IDP.Click to see more details....

All of these settings live under security.authentication.openId in the config.yml file, beneath appConfig for Stroom and proxyConfig for Stroom-Proxy. The structure is identical for both.

A Minimal Configuration

For most providers this is all that is needed:

  security:
    authentication:
      authenticationRequired: true
      openId:
        identityProviderType: EXTERNAL_IDP
        openIdConfigurationEndpoint: "https://IDP_HOST/.well-known/openid-configuration"
        clientId: "StroomClient"
        clientSecret: "THE_CLIENT_SECRET"
        logoutEndpoint: "https://IDP_HOST/logout"

Stroom fetches the provider’s configuration document from openIdConfigurationEndpoint at startup and takes the issuer, authorization endpoint, token endpoint and JWKS URI from it. The logout endpoint is not part of that document, so it is set separately.

If you also want data receipt to be authenticated:

  receive:
    # Require authentication for /datafeed requests
    authenticationRequired: true
    # Allow authentication using an Open ID token
    tokenAuthenticationEnabled: true

Choosing the Identity Provider

identityProviderType

identityProviderType: EXTERNAL_IDP
Value Meaning
INTERNAL_IDP Stroom’s own built in IDP. The default for Stroom, and not valid for Stroom-Proxy.
EXTERNAL_IDP A 3rd party IDP. Stroom’s internal IDP can be the external IDP of a Stroom-Proxy.
NO_IDP No IDP at all. Only for a Stroom-Proxy that forwards to a downstream proxy or Stroom and authenticates with an API key or certificate.

Setting this to EXTERNAL_IDP makes openIdConfigurationEndpoint mandatory; Stroom will refuse to start without it.

Endpoints

openIdConfigurationEndpoint

The provider’s OIDC discovery document, conventionally at https://IDP_HOST/.well-known/openid-configuration. Setting this is much the easiest approach, as Stroom reads the other endpoints from it.

issuer, authEndpoint, tokenEndpoint, jwksUri

Set these only if you are not using a configuration endpoint, or to override a value the provider advertises incorrectly. Anything set here takes precedence over the discovery document.

logoutEndpoint

Where Stroom sends the user to sign out at the provider. This is not part of the discovery document, so it always has to be set by hand, and some providers do not offer one at all.

If it is not set, signing out ends the Stroom session but leaves the user signed in at the provider, so their next visit signs them straight back in without being asked for credentials.

logoutRedirectParamName

logoutRedirectParamName: "post_logout_redirect_uri"

The query parameter Stroom uses to tell the provider where to send the user after signing out. The only permitted values are post_logout_redirect_uri, the default and what the current specification says, and redirect_uri for older providers.

Client Credentials

clientId and clientSecret

The client, sometimes called an application, registered at the provider.

clientSecret may be left unset when the provider authenticates Stroom by mutual TLS instead of a secret.

requestScopes

requestScopes:
  - "openid"
  - "email"

The scopes Stroom asks for during an interactive sign in. Setting this replaces the defaults rather than adding to them, so include openid in whatever you set. Add profile if you need the name, given_name or family_name claims for fullNameClaimTemplate.

clientCredentialsScopes

clientCredentialsScopes:
  - "openid"

The scopes used when Stroom or Stroom-Proxy requests a token for its own service user, rather than for a person. Again, this replaces the default. For Azure AD you will likely need openid and <your-app-id-uri>/.default.

formTokenRequest

formTokenRequest: true

Whether the token request is sent as an HTML form body. Some providers, Cognito among them, require this. It is on by default and rarely needs changing.

Audience Validation

The aud claim of a token names the application the token was minted for. Checking it is what stops a token issued to some other application at the same provider being replayed against Stroom.

Three settings control this.

validateAudience

validateAudience: true

On by default. The audience is checked against allowedAudiences, or against clientId when allowedAudiences is empty.

With identityProviderType: EXTERNAL_IDP and validateAudience left on, at least one of allowedAudiences or clientId must be set. Stroom refuses to start otherwise, rather than letting mandatory validation quietly become a no-op.

allowedAudiences

allowedAudiences: []

A set of acceptable audience values, of which a token must carry at least one. When empty, Stroom validates against clientId instead.

Set this when the provider puts something other than the client id in the aud claim of its access tokens, which is common.

audienceClaimRequired

audienceClaimRequired: true

On by default: a token with no aud claim at all is refused.

Set it to false only for a provider that omits the claim from its access tokens, Cognito being the obvious example. Doing so does not disable validation; an aud claim, where one is present, still has to match.

Token Validation

requiredAccessTokenType

requiredAccessTokenType: null

The JOSE typ header value a token must carry to be accepted as a bearer access token on the API, for example at+jwt for a provider following RFC 9068 , or Bearer for KeyCloak.

When set, a token of any other type, such as an id_token, is refused on the API even though its signature is perfectly valid. That prevents an id_token, which is meant only to tell Stroom who signed in, being replayed as an access token.

Leave it unset, the default, to accept any type. Set it once you have confirmed what your provider actually puts in that header; decoding the header of a real access token is the reliable way to find out.

This applies only to bearer tokens on the API. It has no effect on the interactive sign in flow or on an AWS load balancer data token.

validIssuers

validIssuers: []

Additional issuers to accept beyond the one the provider advertises.

Stroom checks that the issuer in the provider’s configuration response is consistent with openIdConfigurationEndpoint. Where a provider legitimately reports an issuer that is not a parent path of that endpoint, list it here so the check passes.

Signature Algorithms

Not configurable. Stroom accepts RS256/384/512, PS256/384/512 and ES256/384/512, and refuses unsigned tokens and tokens signed with an HMAC algorithm.

There is no reason to expect a mainstream provider to fall foul of this.

Claims

uniqueIdentityClaim

uniqueIdentityClaim: "sub"

The claim used to link an identity at the provider to a Stroom user. It must be unique at the provider and must never change for a given person, which is why sub is the default and normally the right answer.

userDisplayNameClaim

userDisplayNameClaim: "preferred_username"

A friendlier name for the user in the Stroom UI. Not used for identity, so it need not be unique and may change.

Change it if your provider does not issue preferred_username; email is the usual alternative.

fullNameClaimTemplate

fullNameClaimTemplate: '${name}'

Builds the user’s full name from claim values, for example '${given_name} ${family_name}'. Claim names are case sensitive.

AWS Load Balancer Authentication

These apply when an AWS Application Load Balancer in front of Stroom performs the authentication and passes the result on in an x-amzn-oidc-data header.

expectedSignerPrefixes

expectedSignerPrefixes: []

The Amazon Resource Names of the load balancer(s) fronting Stroom, used to verify the signer in the JWT header. Each value is the first N characters of an ARN and must include at least everything up to the colon after the account id, i.e. arn:aws:elasticloadbalancing:region-code:account-id:.

publicKeyUriPattern

publicKeyUriPattern: 'https://public-keys.auth.elb.${awsRegion}.amazonaws.com/${keyId}'

The pattern used to build the URI the load balancer’s public key is fetched from. Supports the ${awsRegion} and ${keyId} variables, each of which may appear more than once. Use single quotes, as with fullNameClaimTemplate.

Stroom-Proxy

Stroom-Proxy takes the same security.authentication.openId block, under proxyConfig. identityProviderType: INTERNAL_IDP is not valid for a proxy; use EXTERNAL_IDP, or NO_IDP where the proxy has no OIDC infrastructure available to it.

A proxy has no interactive users, so the settings concerned with the sign in flow, i.e. the redirect URIs, requestScopes and the claim settings, do not come into play. What it needs is the ability to obtain a token for its own service user via the client credentials grant, and to validate tokens on data it receives.

  receive:
    # Require authentication for /datafeed requests
    authenticationRequired: true
    # Allow authentication using an Open ID token
    tokenAuthenticationEnabled: true
  security:
    authentication:
      openId:
        identityProviderType: EXTERNAL_IDP
        openIdConfigurationEndpoint: "https://IDP_HOST/.well-known/openid-configuration"
        clientId: "StroomProxyClient"
        clientSecret: "THE_CLIENT_SECRET"

Where the proxy forwards data to another proxy or to Stroom, it can attach a token for its service user, provided the destination is configured against the same provider:

  forwardHttpDestinations:
      # Adds a token for the service user to the request
    - addOpenIdAccessToken: true
      enabled: true
      name: "downstream"
      forwardUrl: "http://somehost/stroom/datafeed"

The client used by the proxy needs the client credentials grant enabled at the provider, and the destination must be willing to accept the audience that grant produces. Not every provider supports issuing an OIDC token for a client credentials grant, so check the provider page.

Troubleshooting

Stroom will not start

If identityProviderType is set to ‘EXTERNAL’, property openIdConfigurationEndpoint must be set.

EXTERNAL_IDP requires a discovery endpoint. If your provider genuinely has none, you cannot use this validation route; set the individual endpoints instead and raise it as an issue.

When identityProviderType is EXTERNAL_IDP and validateAudience is true (the default), you must configure either allowedAudiences or clientId

Stroom will not start with audience validation switched on and nothing to validate against, rather than let the check quietly become a no-op. Set clientId, which you almost certainly want anyway, or allowedAudiences.

Issuer ‘X’ obtained from configuration endpoint Y does not share the same base URI.

The provider is advertising an issuer that is not a parent path of the endpoint the document was fetched from, which the OIDC discovery specification says it should be. Some providers do not follow this. Where the value is genuinely correct for your provider, add it to validIssuers.

Issuer ‘X’ obtained from configuration endpoint Y does not match those in the ‘issuer’ or ‘validIssuers’ properties.

You have set issuer or validIssuers, and what the provider advertised is not among them. Correct the configured value, or add the advertised one.

The provider refuses the sign in

An error at the provider, before the user gets back to Stroom, is almost always the redirect URI. Check that https://STROOM_FQDN/api/auth/flow/v1/signin-oidc is registered exactly, using the same scheme, host, port and path prefix as appConfig.publicUri.

This is the single most common problem when upgrading, because Stroom used to send a different redirect URI for every page.

Sign in works but API calls are refused

Interactive sign in validates the id_token, whereas the API validates an access token, and providers treat the two differently. So sign in working tells you the client id, secret and endpoints are all correct, and points at the token validation settings.

In order of likelihood:

  1. Audience. The access token’s aud claim does not match clientId or allowedAudiences, or the token has no aud claim and audienceClaimRequired is true. See Audience validation.
  2. Token type. requiredAccessTokenType is set to something the provider does not put in the token’s typ header. Unset it, or correct it to the value the provider actually uses.
  3. Token type, the other way round. The caller is presenting an id_token rather than an access token. Setting requiredAccessTokenType is what catches this.

Enable debug logging for stroom.security.common.impl.StandardJwtContextFactory to see the issuers, audiences and settings actually in use when a token is validated.

Users sign in but can see nothing

That is expected for a new user. Authentication is all the provider does; permissions are granted in Stroom, and a new user has none. See Users and permissions.

If an administrator you set up with manage_users cannot see anything either, remember that permissions are cached, so a restart may be needed if Stroom was running when the command was issued.

Signing out does not sign the user out of the provider

Either logoutEndpoint is unset, or the provider has no OIDC sign out endpoint, as is the case for Google. The Stroom session ends either way, but the provider’s session does not, so the user’s next visit signs them straight back in.

3.2 - KeyCloak

How to set up KeyCloak as an external identity provider for Stroom.

This is a guide to setting up a new Stroom instance or cluster with KeyCloak as the 3rd party Identity Provider (IDP) Identity Provider (IDP) An Identity Provider is a system or service that can authenticate a user and assert their identity. Identity providers can support single sign on (SSO), which allows the user to sign in once to the Identity Provider so they are then authenticated to all systems using that IDP.Click to see more details.... It assumes you have deployed a new instance or cluster of Stroom and have not yet started it.

Running KeyCloak

If you already have a KeyCloak instance running then move on to the next section.

This section is not a definitive guide to running or administering KeyCloak. It describes how to run KeyCloak using non-production settings for simplicity and to demonstrate using a 3rd party IDP. You should consult the KeyCloak documentation on how to set up a production ready instance.

The easiest way to run KeyCloak is using Docker. To create a KeyCloak container do the following:

docker create \
  --name keycloak \
  -p 9999:8080 \
  -e KEYCLOAK_ADMIN=admin \
  -e KEYCLOAK_ADMIN_PASSWORD=admin \
  quay.io/keycloak/keycloak:20.0.1 \
  start-dev

This example maps KeyCloak’s port to port 9999 to avoid any clash with Stroom that also runs on 8080. This will create a docker container called keycloak that uses an embedded H2 database to hold its state.

To start the container in the foreground, do:

docker start -a keycloak

KeyCloak should now be running on http://localhost:9999/admin . If you want to run KeyCloak on a different port then delete the container and create it with a different port for the -p argument.

Log into KeyCloak using the username admin and password admin as specified in the environment variables set in the container creation command above. You should see the admin console.

Creating a Realm

First you need to create a Realm.

  1. Click on the drop-down in the left pane that contains the word master.
  2. Click Create Realm.
  3. Set the Realm name to StroomRealm.
  4. Click Create.

Creating a Client

In the new realm click on Clients in the left pane, then Create client.

  1. Set the Client ID to StroomClient.
  2. Click Next.
  3. Set Client authentication to on, which makes this a confidential client.
  4. Ensure the following are ticked:
    • Standard flow
    • Direct access grants
  5. Click Save.

Open the new Client and on the Settings tab set:

  • Valid redirect URIs to https://STROOM_FQDN/api/auth/flow/v1/signin-oidc
  • Valid post logout redirect URIs to https://STROOM_FQDN/*

Where STROOM_FQDN is the public address of Stroom, i.e. what you have set as appConfig.publicUri.

The post logout redirect URI does use a wildcard, because Stroom appends a state parameter to it.

On the Advanced tab, under Advanced settings, set Proof Key for Code Exchange Code Challenge Method to S256. Stroom always sends a PKCE challenge, so KeyCloak can be told to insist on one.

On the Credentials tab copy the Client secret for use later in Stroom config.

Adding an Audience Mapper

This step matters, and is easy to miss.

By default KeyCloak does not put the client id in the aud claim of the access tokens it issues; typically it puts account there instead. Stroom validates the audience of every token it is given, so without this step API calls made with a KeyCloak access token are refused. Interactive sign in still works, because the id_token does carry the client id.

In the realm, click Client scopes in the left pane, then the StroomClient-dedicated scope belonging to the client.

  1. Click Add mapper => By configuration => Audience.
  2. Set Name to stroom-audience.
  3. Set Included Client Audience to StroomClient.
  4. Ensure Add to access token is on.
  5. Click Save.

The alternative, if you would rather not change KeyCloak, is to tell Stroom what KeyCloak actually issues:

        allowedAudiences:
          - "account"

That is weaker, since account is an audience every client in the realm can obtain, so a token minted for another application in the same realm would be accepted by Stroom. Prefer the mapper.

Creating Users

Click on Users in the left pane then Add user. Set the following:

  • Username - admin
  • First name - Administrator
  • Last name - Administrator

Click Create.

Select the Credentials tab and click Set password.

Set the password to admin and set Temporary to off.

Repeat this process for the following user:

  • Username - jbloggs
  • First name - Joe
  • Last name - Bloggs
  • Password - password

Configure Stroom for KeyCloak

Edit the config.yml file and set the following values:

  receive:
    # Set to true to require authentication for /datafeed requests
    authenticationRequired: true
    # Set to true to allow authentication using an Open ID token
    tokenAuthenticationEnabled: true
  security:
    authentication:
      authenticationRequired: true
      openId:
        # Tells Stroom to use an external IDP for authentication
        identityProviderType: EXTERNAL_IDP
        # The endpoint to obtain the rest of the IDP's configuration. Specific to the realm/issuer.
        openIdConfigurationEndpoint: "http://localhost:9999/realms/StroomRealm/.well-known/openid-configuration"
        # The client ID created in KeyCloak
        clientId: "StroomClient"
        # The client secret copied from KeyCloak above
        clientSecret: "XwTPPudGZkDK2hu31MZkotzRUdBWfHO6"
        # The URL on the IDP to redirect users to when logging out of Stroom
        logoutEndpoint: "http://localhost:9999/realms/StroomRealm/protocol/openid-connect/logout"
        # KeyCloak stamps its access tokens with a 'typ' header of 'Bearer'. Requiring it stops an
        # id_token being replayed against the API as though it were an access token.
        requiredAccessTokenType: "Bearer"

These values are obtained from the IDP. In the case of KeyCloak they can be found by clicking on Realm settings => Endpoints => OpenID Endpoint Configuration and extracting the various values from the JSON response. Alternatively they can typically be found at https://host/.well-known/openid-configuration on any Open ID Connect IDP. The values will reflect the host and port that the IDP is running on along with the name of the realm.

Setting the above values assumes KeyCloak is running on localhost:9999 and the realm name is StroomRealm.

The claim defaults suit KeyCloak, so there is nothing to set for them. KeyCloak issues preferred_username, which Stroom uses as the display name, and issues name where the user has a first and last name, which satisfies the default fullNameClaimTemplate of ${name}.

Setting up the Admin User in Stroom

Now that the admin user exists in the IDP we need to grant it Administrator rights in Stroom.

In the Users section of KeyCloak click on user admin. On the Details tab copy the value of the ID field. The ID is in the form of a UUID UUID A Universally Unique Identifier for uniquely identifying something. UUIDs are used as the identifier in Doc Refs. An example of a UUID is 4ffeb895-53c9-40d6-bf33-3ef025401ad3.Click to see more details.... This ID is the sub claim, which is what Stroom uses to uniquely identify the user and associate it with the identity in KeyCloak.

To set up Stroom with this admin user run the following (before Stroom has been started for the first time):

subject_id="XXX"; \
java -jar /absolute/path/to/stroom-app-all.jar \
  manage_users \
  --createUser "${subject_id}" \
  --createGroup Administrators \
  --addToGroup "${subject_id}" Administrators \
  --grantPermission Administrators "Administrator" \
  ../local.yml

Where XXX is the user ID copied from the IDP as described above. This command is repeatable as it will skip any users/groups/memberships that already exist.

This command will do the following:

  • Create the Stroom User by creating an entry in the stroom_user database table for the IDP’s admin user.
  • Ensure that an Administrators group exists (i.e. an entry in the stroom_user database table for the Administrators group).
  • Add the admin user to the group Administrators.
  • Grant the application permission Administrator to the group Administrators.

Logging into Stroom

As the Administrator

Now that the user and permissions have been set up in Stroom, the administrator can log in.

First start the Stroom instance or cluster.

Navigate to https://STROOM_FQDN and Stroom should re-direct you to the IDP (KeyCloak) to authenticate. Enter the username admin and password admin. You should be authenticated by KeyCloak and re-directed back to Stroom. Your user ID is shown in the bottom right corner of the Welcome tab.

As an administrator, the

Tools
User Permissions
menu item will be available to manage the permissions of any users that have logged on at least once.

Now select

User
Logout
to be re-directed to the IDP to log out. Once you log out of the IDP it should re-direct you back to Stroom, which will send you to the IDP login screen to log back in again.

As an Ordinary User

On the IDP login screen, log in as user jbloggs with the password password. You will be re-directed to Stroom, however the explorer tree will be empty and most of the menu items will be disabled. In order to gain permissions to do anything in Stroom, a Stroom administrator will need to grant application and document permissions and/or group memberships to the user via the

Tools
User Permissions
menu item.

Configure Stroom-Proxy for KeyCloak

Create a second client in KeyCloak for the proxy, following the steps above but with Service accounts roles enabled so that it can use the client credentials grant. A proxy has no interactive users, so it needs no redirect URIs.

Edit the proxy’s config.yml file and set the following values:

  receive:
    # Set to true to require authentication for /datafeed requests
    authenticationRequired: true
    # Set to true to allow authentication using an Open ID token
    tokenAuthenticationEnabled: true
  security:
    authentication:
      openId:
        identityProviderType: EXTERNAL_IDP
        openIdConfigurationEndpoint: "http://localhost:9999/realms/StroomRealm/.well-known/openid-configuration"
        clientId: "StroomProxyClient"
        clientSecret: "THE_PROXY_CLIENT_SECRET"
        logoutEndpoint: "http://localhost:9999/realms/StroomRealm/protocol/openid-connect/logout"

If Stroom-Proxy is configured to forward data on to another Stroom-Proxy or Stroom instance then it can use tokens when forwarding that data. This assumes the downstream Stroom or Stroom-Proxy is also configured to use the same external IDP.

  forwardHttpDestinations:

      # If true, adds a token for the service user to the request
    - addOpenIdAccessToken: true
      enabled: true
      name: "downstream"
      forwardUrl: "http://somehost/stroom/datafeed"

The token used will be for the service user account of the identity provider client used by Stroom-Proxy.

That token’s audience is validated at the destination just like any other, so the destination needs either an audience mapper on the proxy’s client, or the audience the proxy’s tokens actually carry listed in its allowedAudiences.

3.3 - Amazon Cognito

How to set up an Amazon Cognito user pool as an external identity provider for Stroom.

This page covers using an Amazon Cognito user pool as Stroom’s Identity Provider (IDP) Identity Provider (IDP) An Identity Provider is a system or service that can authenticate a user and assert their identity. Identity providers can support single sign on (SSO), which allows the user to sign in once to the Identity Provider so they are then authenticated to all systems using that IDP.Click to see more details....

Cognito differs from a typical OIDC provider in two ways that directly affect the Stroom configuration, so they are worth knowing before you start.

  • Its access tokens carry no aud claim, using client_id instead. Stroom requires an audience claim by default, so this has to be turned off.
  • Its authorization, token and sign out endpoints belong to the hosted UI domain, which is separate from the user pool’s issuer host.

Creating the User Pool and App Client

In the AWS console, under Cognito:

  1. Create a user pool, or use an existing one.
  2. Configure a domain for the pool, either a Cognito prefix domain giving https://YOUR_PREFIX.auth.REGION.amazoncognito.com, or your own custom domain. This provides the hosted UI and the OAuth endpoints, and is required.
  3. Create an app client of the confidential type, i.e. one with a client secret.
  4. Enable the Authorization code grant for the client. Do not enable the implicit grant.
  5. Set the OpenID Connect scopes to at least openid and email.
  6. Set the Allowed callback URL to https://STROOM_FQDN/api/auth/flow/v1/signin-oidc.
  7. Set the Allowed sign out URL to https://STROOM_FQDN/.
  8. Note the app client id and app client secret, and the user pool id.

Where STROOM_FQDN is the public address of Stroom, i.e. what you have set as appConfig.publicUri.

Cognito supports PKCE, and Stroom always sends an S256 challenge, so there is nothing to configure for it.

The Endpoints

Two different hosts are involved.

Purpose Host
Issuer, discovery document, JWKS https://cognito-idp.REGION.amazonaws.com/USER_POOL_ID
Authorization, token, sign out Your pool’s domain, e.g. https://YOUR_PREFIX.auth.REGION.amazoncognito.com

The discovery document is at:

https://cognito-idp.REGION.amazonaws.com/USER_POOL_ID/.well-known/openid-configuration

Set openIdConfigurationEndpoint to it, so that Stroom picks up the issuer and the JWKS URI.

Set authEndpoint and tokenEndpoint explicitly to your pool’s domain, since those are the endpoints your users and Stroom actually need to reach:

  • https://YOUR_PREFIX.auth.REGION.amazoncognito.com/oauth2/authorize
  • https://YOUR_PREFIX.auth.REGION.amazoncognito.com/oauth2/token

Configuring Stroom

  receive:
    # Set to true to require authentication for /datafeed requests
    authenticationRequired: true
    # Set to true to allow authentication using an Open ID token
    tokenAuthenticationEnabled: true
  security:
    authentication:
      authenticationRequired: true
      openId:
        identityProviderType: EXTERNAL_IDP
        openIdConfigurationEndpoint: "https://cognito-idp.eu-west-2.amazonaws.com/eu-west-2_ABC123456/.well-known/openid-configuration"
        # The hosted UI endpoints, which are on the pool's domain rather than the issuer host
        authEndpoint: "https://mydomain.auth.eu-west-2.amazoncognito.com/oauth2/authorize"
        tokenEndpoint: "https://mydomain.auth.eu-west-2.amazoncognito.com/oauth2/token"
        logoutEndpoint: "https://mydomain.auth.eu-west-2.amazoncognito.com/logout"
        # The app client id and secret
        clientId: "1h57kf5cpparlm9m52319hsnrf"
        clientSecret: "THE_APP_CLIENT_SECRET"
        # Cognito requires the token request to be sent as a form. This is the default.
        formTokenRequest: true
        # Cognito access tokens carry no 'aud' claim, so an absent one must not be a failure.
        # An 'aud' claim that IS present, as on an id_token, is still validated against clientId.
        audienceClaimRequired: false
        # Cognito does not issue 'preferred_username'
        userDisplayNameClaim: "cognito:username"

Audience Validation

This is the setting most likely to catch you out.

A Cognito id_token, used by interactive sign in, carries aud set to the app client id, so it validates against clientId with no further configuration.

A Cognito access token, used for API calls, carries no aud claim at all; the equivalent information is in a client_id claim, which is not something Stroom validates against. With the default of audienceClaimRequired: true those tokens are refused, so set it to false.

Leave validateAudience at its default of true. Setting it to false would switch off audience checking for the id_token as well, which Cognito populates perfectly well.

Claims

Cognito does not issue a preferred_username claim unless the user pool has been set up with that attribute, so the Stroom default for userDisplayNameClaim will usually not resolve. Use cognito:username, or email where every user has one.

uniqueIdentityClaim should be left as sub, which for Cognito is a UUID that is stable for the life of the user.

For fullNameClaimTemplate to resolve, the corresponding attributes must be populated on the user and included in the token. Add profile to requestScopes if you need name, given_name or family_name.

Signing Out

Cognito’s sign out endpoint has historically expected the return address in a logout_uri parameter rather than the post_logout_redirect_uri that Stroom sends.

Check whether sign out returns your users to Stroom. If it leaves them on an error page at Cognito, try:

        logoutRedirectParamName: "redirect_uri"

Those two values are the only ones Stroom accepts. If neither works with your pool, leave logoutEndpoint unset; signing out will then end the Stroom session without signing the user out of Cognito, which means their next visit will sign them straight back in without being asked for credentials.

Access Token Type

Leave requiredAccessTokenType unset unless you have decoded the header of a real Cognito access token and confirmed what it contains. It is a hardening measure, and setting it to a value your provider does not use will refuse every API call.

Setting up the Admin User in Stroom

The bootstrap process is the same as for any provider. Find the sub of the user who is to be the administrator, which for Cognito is the user’s UUID as shown in the console, then run the manage_users command before starting Stroom for the first time.

subject_id="XXX"; \
java -jar /absolute/path/to/stroom-app-all.jar \
  manage_users \
  --createUser "${subject_id}" \
  --createGroup Administrators \
  --addToGroup "${subject_id}" Administrators \
  --grantPermission Administrators "Administrator" \
  ../local.yml

Stroom-Proxy with Cognito

A Stroom-Proxy obtains a token for its own service user using the client credentials grant.

In Cognito that grant requires a resource server with custom scopes defined on it, and the resulting tokens carry those custom scopes rather than openid. Set clientCredentialsScopes to the custom scopes you have defined:

  security:
    authentication:
      openId:
        identityProviderType: EXTERNAL_IDP
        openIdConfigurationEndpoint: "https://cognito-idp.eu-west-2.amazonaws.com/eu-west-2_ABC123456/.well-known/openid-configuration"
        tokenEndpoint: "https://mydomain.auth.eu-west-2.amazoncognito.com/oauth2/token"
        clientId: "THE_PROXY_APP_CLIENT_ID"
        clientSecret: "THE_PROXY_APP_CLIENT_SECRET"
        formTokenRequest: true
        audienceClaimRequired: false
        clientCredentialsScopes:
          - "https://stroom.example.com/api.write"

The destination the proxy forwards to must be configured to accept the tokens this produces, which again means audienceClaimRequired: false at that end.

3.4 - Google

How to set up Google as an external identity provider for Stroom.

This page covers using Google Identity as Stroom’s Identity Provider (IDP) Identity Provider (IDP) An Identity Provider is a system or service that can authenticate a user and assert their identity. Identity providers can support single sign on (SSO), which allows the user to sign in once to the Identity Provider so they are then authenticated to all systems using that IDP.Click to see more details..., whether for consumer Google accounts or for a Google Workspace domain.

Creating the OAuth Client

In the Google Cloud Console :

  1. Select or create a project.
  2. Configure the OAuth consent screen. For a Workspace domain choose the Internal user type, which restricts sign in to your own domain. For consumer accounts the only option is External.
  3. Go to APIs & Services => Credentials => Create Credentials => OAuth client ID.
  4. Choose an application type of Web application.
  5. Under Authorised redirect URIs, add https://STROOM_FQDN/api/auth/flow/v1/signin-oidc.
  6. Create the client and note the Client ID and Client secret.

Where STROOM_FQDN is the public address of Stroom, i.e. what you have set as appConfig.publicUri.

Google supports PKCE, and Stroom always sends an S256 challenge, so there is nothing to configure for it.

There is no sign out URL to register, because Google has no OIDC sign out endpoint to register one with.

Configuring Stroom

  security:
    authentication:
      authenticationRequired: true
      openId:
        identityProviderType: EXTERNAL_IDP
        openIdConfigurationEndpoint: "https://accounts.google.com/.well-known/openid-configuration"
        clientId: "123456789012-abcdefghijklmnop.apps.googleusercontent.com"
        clientSecret: "THE_CLIENT_SECRET"
        # Google issues no 'preferred_username' claim
        userDisplayNameClaim: "email"
        # 'profile' is needed for the 'name' claim used by fullNameClaimTemplate
        requestScopes:
          - "openid"
          - "email"
          - "profile"

The discovery document supplies the issuer, https://accounts.google.com, along with the authorization, token and JWKS endpoints, so none of those need setting by hand.

Note that logoutEndpoint is deliberately absent; see Signing out below.

Audience Validation

Nothing to do. Google’s id_token carries aud set to your client id, so it validates against clientId with the default settings.

Claims

Google issues sub, email, email_verified, name, given_name, family_name and picture, and hd for a Workspace account. It does not issue preferred_username, which is Stroom’s default for userDisplayNameClaim, so that has to be changed. email is the natural choice.

name, given_name and family_name require the profile scope, which is why it is added to requestScopes above. Without it the default fullNameClaimTemplate of ${name} will not resolve.

Leave uniqueIdentityClaim as sub. Google’s sub is stable for a given account, unlike the email address.

Signing Out

Google offers no OIDC sign out endpoint, so leave logoutEndpoint unset.

Logging out of Stroom then ends the Stroom session but leaves the user signed in to Google. Their next visit to Stroom will sign them straight back in without being asked for credentials, which is worth being aware of on a shared machine.

Do not point logoutEndpoint at a general Google sign out URL, as that would sign the user out of every Google service on that browser, which is unlikely to be what they expect from a Stroom logout.

Access Token Type

Leave requiredAccessTokenType unset. It applies to JWT bearer tokens on the API, and Google’s access tokens are not JWTs.

Restricting Who Can Sign In

Authentication and authorisation are separate. Anyone Google will authenticate can complete a sign in and have a Stroom user created for them, but that user starts with no permissions and no group memberships, so they can see nothing.

Even so, you should restrict who can reach the sign in at all:

  • For a Workspace domain, set the OAuth consent screen to Internal, so only accounts in your domain can authenticate.
  • For consumer accounts there is no equivalent, so any Google account can reach the consent screen. Consider whether Google is the right provider in that case.

Stroom has no configuration to restrict sign in by hd or email domain, so this has to be done at Google.

Setting up the Admin User in Stroom

Find the sub of the account that is to be the administrator. Unlike KeyCloak and Cognito, Google does not show this in an admin console; the reliable way to obtain it is to decode an id_token issued for that account, or read it from Stroom’s logs after the person has signed in once.

The simplest route is therefore:

  1. Configure Stroom as above and start it.
  2. Have the intended administrator sign in once. They will land in Stroom with no permissions.
  3. Read their sub from the Stroom logs, or from the
    Tools
    Users
    screen if another administrator is available.
  4. Run the manage_users command with that value, then restart Stroom so the permission caches are rebuilt.
subject_id="XXX"; \
java -jar /absolute/path/to/stroom-app-all.jar \
  manage_users \
  --createUser "${subject_id}" \
  --createGroup Administrators \
  --addToGroup "${subject_id}" Administrators \
  --grantPermission Administrators "Administrator" \
  ../local.yml

The command is repeatable and will skip anything that already exists, so running it against a user that signed in earlier is fine.

Data Receipt and the API

Because Google’s access tokens are opaque rather than JWTs, Stroom cannot validate them, so this will not work:

  receive:
    authenticationRequired: true
    tokenAuthenticationEnabled: true

Use Stroom API Keys API Key API Keys are a form of authentication token that are created within Stroom for use by Stroom-Proxy instances or other clients that want to use Stroom’s API. It is an encrypted string that contains details of the user and the expiration date of the token. Possession of a valid API Key for a user account means that you can do anything that the user can do in the user interface via the API.Click to see more details... for API clients and for feed status checks, or client certificates for data receipt.

Stroom-Proxy with Google

Google has no OIDC client credentials grant, so a Stroom-Proxy cannot obtain a service user token from it, and addOpenIdAccessToken on a forward destination has nothing to add.

Configure the proxy with identityProviderType: NO_IDP and give it an API key created in Stroom:

  feedStatus:
    apiKey: "AN_API_KEY_CREATED_IN_STROOM"
  security:
    authentication:
      openId:
        identityProviderType: NO_IDP

3.5 - Microsoft Entra ID (Azure AD)

How to set up Microsoft Entra ID, formerly Azure Active Directory, as an external identity provider for Stroom.

This page covers using Microsoft Entra ID as Stroom’s Identity Provider (IDP) Identity Provider (IDP) An Identity Provider is a system or service that can authenticate a user and assert their identity. Identity providers can support single sign on (SSO), which allows the user to sign in once to the Identity Provider so they are then authenticated to all systems using that IDP.Click to see more details.... Entra ID is the current name for what was Azure Active Directory, and much of the tooling and documentation still says Azure AD.

Entra ID has two generations of endpoint, v1.0 and v2.0, which issue tokens with different issuers and different formats. Two of the three things most likely to go wrong here come from mixing them up, so it is worth being deliberate: use the v2.0 endpoints throughout.

Creating the App Registration

In the Microsoft Entra admin centre , or the Azure portal under Microsoft Entra ID:

  1. Go to App registrations => New registration.
  2. Give it a name, e.g. Stroom.
  3. For Supported account types choose Accounts in this organizational directory only, i.e. single tenant, unless you have a specific reason not to. This restricts sign in to your own tenant.
  4. Under Redirect URI select a platform of Web and enter https://STROOM_FQDN/api/auth/flow/v1/signin-oidc.
  5. Click Register, then note the Application (client) ID and the Directory (tenant) ID from the overview page.

Where STROOM_FQDN is the public address of Stroom, i.e. what you have set as appConfig.publicUri.

Then, still in the app registration:

  1. Under Authentication, add a Front-channel logout URL of https://STROOM_FQDN/, and add the same value under Redirect URIs if your tenant requires post logout redirect URIs to be registered.
  2. Under Certificates & secrets => Client secrets, create a new secret and copy its Value immediately, as it is only shown once.

Entra ID supports PKCE, and Stroom always sends an S256 challenge, so there is nothing to configure for it.

Exposing an API for Access Tokens

This step is what makes API authentication work, and is the Entra ID equivalent of KeyCloak’s audience mapper.

If Stroom only ever asks for the openid, email and profile scopes, Entra ID issues an access token for Microsoft Graph rather than for Stroom. Those tokens are intended only for Graph, are not in a format a third party can validate, and will fail validation at Stroom. Interactive sign in still works throughout, because it uses the id_token.

To get an access token that Stroom can validate, the app registration has to expose an API of its own:

  1. Go to Expose an API => Add next to Application ID URI. Accept the default of api://<client-id>, or set your own.
  2. Click Add a scope, name it something like user_impersonation, and choose who can consent.
  3. Under Manifest, set accessTokenAcceptedVersion to 2.

Callers then request that scope, e.g. api://<client-id>/user_impersonation, and the resulting access token carries an aud claim that Stroom can be configured to accept.

Configuring Stroom

  receive:
    # Set to true to require authentication for /datafeed requests
    authenticationRequired: true
    # Set to true to allow authentication using an Open ID token
    tokenAuthenticationEnabled: true
  security:
    authentication:
      authenticationRequired: true
      openId:
        identityProviderType: EXTERNAL_IDP
        # Note the '/v2.0' path part. Without it you get the v1.0 endpoints and a different issuer.
        openIdConfigurationEndpoint: "https://login.microsoftonline.com/TENANT_ID/v2.0/.well-known/openid-configuration"
        # The Application (client) ID from the app registration overview
        clientId: "11111111-2222-3333-4444-555555555555"
        clientSecret: "THE_CLIENT_SECRET_VALUE"
        logoutEndpoint: "https://login.microsoftonline.com/TENANT_ID/oauth2/v2.0/logout"
        # Accept both the id_token audience (the client id) and the access token audience
        # (the Application ID URI). Adjust to match what your tokens actually carry.
        allowedAudiences:
          - "11111111-2222-3333-4444-555555555555"
          - "api://11111111-2222-3333-4444-555555555555"

Replace TENANT_ID with the Directory (tenant) ID.

Issuers

The v2.0 discovery endpoint advertises an issuer of https://login.microsoftonline.com/TENANT_ID/v2.0, which is a parent path of the discovery endpoint itself, so Stroom’s issuer check is satisfied with no extra configuration.

The v1.0 endpoints are not so tidy. Their issuer is https://sts.windows.net/TENANT_ID/, which shares no base URI with the discovery endpoint, and Stroom will refuse to start with:

Issuer ‘X’ obtained from configuration endpoint Y does not share the same base URI.

If you must use v1.0, or you have v1.0 access tokens in circulation from an app registration you cannot change, list the issuer explicitly:

        validIssuers:
          - "https://sts.windows.net/TENANT_ID/"

Using the v2.0 endpoints and accessTokenAcceptedVersion: 2 is much the better answer.

Audience Validation

An Entra ID id_token carries aud set to the Application (client) ID, so interactive sign in validates against clientId with no further configuration.

An access token for your exposed API carries aud set to either the Application ID URI or the client id, depending on accessTokenAcceptedVersion and how the scope was requested. Listing both in allowedAudiences, as above, covers either.

Leave validateAudience at its default of true.

Claims

The Stroom defaults suit Entra ID v2.0. It issues preferred_username, normally the user principal name, which Stroom uses as the display name, and name, which satisfies the default fullNameClaimTemplate of ${name}.

For uniqueIdentityClaim you have a choice:

Claim Notes
sub The Stroom default. In Entra ID this is pairwise, i.e. a different value per application, and stable for the life of that app registration. Delete and recreate the app registration and every user’s sub changes, orphaning their Stroom user.
oid The user’s object id in the directory. Stable across applications and across app registrations, so it survives a re-registration. Unique within a tenant.

oid is the more robust choice for a single tenant deployment, and is what Microsoft’s own guidance points to as the durable identifier. sub is fine if you are confident the app registration will not be recreated.

        uniqueIdentityClaim: "oid"

Group and Role Claims

Entra ID can be configured to emit groups and roles claims. Stroom does not consume them. All authorisation is done with Stroom’s own users, groups and permissions, so directory group membership has no effect on what a user can do in Stroom.

Access Token Type

Leave requiredAccessTokenType unset until you have decoded the header of a real access token from your tenant and confirmed what it contains. Setting it to a value your tokens do not use will refuse every API call.

Setting up the Admin User in Stroom

Find the identifier of the account that is to be the administrator, matching whatever you set uniqueIdentityClaim to.

If you are using oid, it is shown as the Object ID on the user’s page under Users in the Entra admin centre. If you are using sub, it is pairwise and not shown anywhere in the portal, so you will need to decode an id_token issued for that user, or have them sign in once and read it from the Stroom logs.

Then run the following, ideally before Stroom has been started for the first time:

subject_id="XXX"; \
java -jar /absolute/path/to/stroom-app-all.jar \
  manage_users \
  --createUser "${subject_id}" \
  --createGroup Administrators \
  --addToGroup "${subject_id}" Administrators \
  --grantPermission Administrators "Administrator" \
  ../local.yml

The command is repeatable and will skip anything that already exists, so running it against a user who has already signed in is fine. Restart Stroom afterwards if it was running, as permissions are cached.

Stroom-Proxy with Entra ID

A Stroom-Proxy obtains a token for its own service user using the client credentials grant.

Create a second app registration for the proxy, then grant it access to the API exposed by the Stroom app registration:

  1. In the proxy’s app registration, go to API permissions => Add a permission => My APIs and select the Stroom app registration.
  2. Choose Application permissions, which is the client credentials case, rather than delegated permissions.
  3. Have a directory administrator grant admin consent, without which the grant will fail.

Entra ID’s client credentials flow uses the .default scope of the target API:

  security:
    authentication:
      openId:
        identityProviderType: EXTERNAL_IDP
        openIdConfigurationEndpoint: "https://login.microsoftonline.com/TENANT_ID/v2.0/.well-known/openid-configuration"
        clientId: "THE_PROXY_CLIENT_ID"
        clientSecret: "THE_PROXY_CLIENT_SECRET"
        clientCredentialsScopes:
          - "api://11111111-2222-3333-4444-555555555555/.default"

The destination the proxy forwards to must accept the audience these tokens carry, which will be the Application ID URI or client id of the Stroom app registration, so make sure it appears in that destination’s allowedAudiences.

4 - Edge Proxy as the Relying Party

Running Stroom behind an authenticating reverse proxy, such as an AWS Application Load Balancer with Cognito, that completes the Open ID Connect flow itself.

Normally Stroom is its own Open ID Connect client, or Relying Party: it redirects the browser to the Identity Provider (IDP) Identity Provider (IDP) An Identity Provider is a system or service that can authenticate a user and assert their identity. Identity providers can support single sign on (SSO), which allows the user to sign in once to the Identity Provider so they are then authenticated to all systems using that IDP.Click to see more details..., exchanges the authorization code for tokens, and holds them in its session. That is the model described by Internal IDP and External IDP.

Some environments put an authenticating reverse proxy in front of Stroom instead. The proxy completes the OIDC flow before a request ever reaches Stroom, holds the tokens itself, and injects a verified credential into each request it forwards. Examples include:

  • An AWS Application Load Balancer with an authenticate-cognito or authenticate-oidc listener rule, which injects a signed x-amzn-oidc-data header.
  • NGINX with oauth2-proxy (or NGINX Plus’s native OIDC support, or lua-resty-openidc), which relays the IDP’s token as an Authorization: Bearer header.

This is common in cloud and government estates where a policy requires that unauthenticated traffic never reaches the application. Stroom supports it as a first class deployment model.

The One Rule: Exactly One Relying Party

For any given path, exactly one component runs the OIDC flow — the proxy, or Stroom, never both.

If Stroom is left in its normal configuration behind an authenticating proxy, both try to be the Relying Party. The browser is driven through a second, redundant OIDC flow stacked on the one the proxy already completed, which needs a second client registration at the IDP, doubles the cookies on every request, and typically fails with Stroom Loading, Authentication Error: Failed to Fetch.

Setting edgeAuthentication.enabled tells Stroom the proxy owns the flow. Stroom then:

  • Accepts the proxy’s injected credential, verified cryptographically on every request, as the user’s identity. No Stroom session is created; the identity is re-derived from the headers each time, which is also how the proxy’s own token refresh reaches Stroom.
  • Never starts an OIDC flow of its own, and disables its OIDC callback endpoint.
  • Treats the injected credential as needing Cross-Site Request Forgery (CSRF) protection on browser requests, because the browser attaches the proxy’s session cookie automatically, even to cross site requests.
  • Can end the proxy’s session on logout, not just its own.

Stroom Configuration

  security:
    authentication:
      edgeAuthentication:
        enabled: true
        logout:
          cookiesToExpire: [ "AWSELBAuthSessionCookie" ]
          signOutUrl: "https://MY_DOMAIN.auth.REGION.amazoncognito.com/logout?client_id=CLIENT_ID&logout_uri=POST_LOGOUT_URI"
      openId:
        identityProviderType: EXTERNAL_IDP
        # ... provider settings, see the worked examples ...

edgeAuthentication.enabled

Declares that the proxy is the Relying Party, with the effects described above. Requires identityProviderType: EXTERNAL_IDP; Stroom will refuse to start otherwise.

edgeAuthentication.logout.cookiesToExpire

Signing out of Stroom does not end the proxy’s session by itself; without help, the very next request would silently sign the user straight back in. This setting lists the proxy’s session cookie name prefixes, which Stroom expires when the user logs out.

They are prefixes because proxies shard large session cookies: an ALB’s AWSELBAuthSessionCookie arrives as AWSELBAuthSessionCookie-0, -1 and so on, and oauth2-proxy chunks _oauth2_proxy the same way.

edgeAuthentication.logout.signOutUrl

Where to send the browser after logging out of Stroom, normally the proxy’s or IDP’s own sign out endpoint, so the session ends everywhere. For Cognito this is the hosted UI’s /logout endpoint; for oauth2-proxy it is /oauth2/sign_out.

If it is not set, Stroom logs a warning at each logout: the proxy session survives, and the user may be signed straight back in.

csrf.protectBrowserOriginatedRequests

On by default, and independent of edgeAuthentication. It rejects a state changing request whose token arrived on a request the browser marked as cross site, unless the request carries the X-CSRF header. Browsers do not let a cross site page attach an Authorization header, so such a token can only have been injected by a proxy — this is the safety net for a proxy that nobody declared in the configuration.

Non browser clients are unaffected, as they send none of the browser fetch metadata this check relies on.

What the Proxy Must and Must Not Authenticate

Stroom is not only a web application; it ingests data, serves health checks and its nodes talk to each other. None of that traffic can complete an interactive sign in, so the proxy’s authenticate rule must cover the browser facing paths only.

Path Proxy rule Why
/, /stroom/*, /ui/* Authenticate The UI
/api/* Authenticate Browser API calls
/datafeed (and its legacy aliases) Bypass Data receipt from Stroom-Proxies and clients, authenticated by certificate, token or API key
/remoting/remotefeedservice.rpc Bypass Feed status RPC
/status Bypass Health checks
Admin port (/stroomAdmin) Bypass Should not be publicly exposed at all

Stroom still authenticates the bypassed paths itself — bypassing the proxy does not bypass Stroom’s own checks.

Node to node traffic inside a cluster does not go through the proxy and needs no special handling.

Trust Prerequisites

Stroom verifies the signature of whatever credential the proxy injects, so a forged header does not authenticate. Two things must still be true of the deployment, and Stroom cannot verify them from the inside:

  1. Stroom is unreachable except through the proxy — a security group, firewall rule or network policy allowing traffic to Stroom’s application port only from the proxy.
  2. The proxy overwrites the headers it injects, so a client cannot supply its own. The ALB does this for its x-amzn-oidc-* headers; with NGINX make sure proxy_set_header is used for the Authorization header, which overwrites, and nothing upstream re-adds it.

Request Header Sizes

Authenticating proxies make requests big. An ALB’s session cookie is sharded at 4KB per shard, and the injected token headers come on top, so an ordinary authenticated request can exceed the 8KB per request default that Jetty applies when nothing is configured. The failure looks like a network error, not an authentication error.

Set a larger limit on every Stroom node:

server:
  applicationConnectors:
    - type: http
      port: 8080
      useForwardedHeaders: true
      maxRequestHeaderSize: 32KiB

User Accounts and Permissions

Exactly as with any external IDP, the proxy establishes who the user is; Stroom still decides what they may do. A Stroom user record is created automatically the first time a verified identity is seen, with no permissions. Anyone the IDP will authenticate can therefore reach an empty Stroom UI, so if that is not wanted, restrict who can authenticate at the IDP or proxy (for example, limit the Cognito app client or the ALB rule to a group).

Worked Examples

  • AWS ALB and Cognito - the load balancer authenticates against a Cognito user pool and injects a signed x-amzn-oidc-data header.
  • NGINX, oauth2-proxy and KeyCloak - the proxy authenticates against KeyCloak (or any OIDC provider) and relays the IDP’s token as a bearer header.

Troubleshooting

Symptom Likely cause
Authentication Error: Failed to Fetch at the loading screen edgeAuthentication.enabled not set, so Stroom started a second flow of its own; or the proxy session lapsed (Stroom reloads the page once to let the proxy re-authenticate, then shows this)
Browser bounces between Stroom and the IDP forever Two Relying Parties: Stroom is running its own flow behind the proxy. Set edgeAuthentication.enabled
HTTP 403 with Authenticated user is not permitted to use stroom The proxy’s credential verified, but the user is unknown or disabled in Stroom, or the token could not be validated - check the issuer and (for an ALB) expectedSignerPrefixes
Requests fail with what looks like a network error Header size - set maxRequestHeaderSize
Data feeds or health checks broken The proxy’s authenticate rule covers a machine path - see the path table above
Signing out signs the user straight back in logout.cookiesToExpire / logout.signOutUrl not set, or the post logout page is behind the proxy’s authenticate rule

4.1 - AWS ALB and Cognito

Running Stroom behind an AWS Application Load Balancer that authenticates users against an Amazon Cognito user pool.

In this deployment the Application Load Balancer is the Open ID Connect Relying Party. Its listener rule sends unauthenticated browsers to Cognito, completes the code flow, holds the session in AWSELBAuthSessionCookie cookies, and forwards each authenticated request to Stroom with three extra headers:

Header Contents
x-amzn-oidc-data The user’s claims as a JWT, signed by the ALB with a regional AWS key (ES256)
x-amzn-oidc-accesstoken The access token from Cognito, in plain text
x-amzn-oidc-identity The sub claim, in plain text

Stroom authenticates the request by verifying the x-amzn-oidc-data signature against AWS’s regional public key endpoint, checking the token’s issuer against the configured one, and checking that the signing load balancer is one of yours.

Cognito Setup

Create a user pool, hosted UI domain and app client as described on the Cognito page, with these differences:

  • The app client belongs to the ALB, not to Stroom, so its allowed callback URL is the ALB’s own: https://STROOM_FQDN/oauth2/idpresponse (this fixed path is handled by the load balancer itself and never reaches Stroom).
  • The client must have a client secret and use the code grant; the ALB requires both.
  • Register the post logout landing page as an allowed sign out URL for the client (see Logout).

No second app client for Stroom is needed. The ALB is the only OIDC client in this topology.

Load Balancer Setup

Order the listener rules so machine traffic is forwarded without authentication, then authenticate everything else:

  1. Paths /datafeed*, /stroom/datafeed*, /remoting/*, /statusforward to the Stroom target group.
  2. Default → authenticate-cognito (your user pool, app client and hosted UI domain) then forward to the Stroom target group.

Points worth knowing:

  • SessionCookieName defaults to AWSELBAuthSessionCookie; if you change it, change edgeAuthentication.logout.cookiesToExpire to match.
  • The session cookie is sharded at 4KB per shard (-0, -1, …), which is why the header size limit matters.
  • If the total claims and access token exceed 11KB the ALB itself returns HTTP 500 and increments its ELBAuthUserClaimsSizeExceeded metric — trim what the IDP puts in the token if you hit this.
  • Restrict the Stroom target’s security group to accept traffic only from the ALB’s security group; this is trust prerequisite one.

Stroom Configuration

server:
  applicationConnectors:
    - type: http
      port: 8080
      useForwardedHeaders: true
      maxRequestHeaderSize: 32KiB

appConfig:
  publicUri: "https://STROOM_FQDN"    # the ALB's public address
  security:
    authentication:
      edgeAuthentication:
        enabled: true
        logout:
          cookiesToExpire: [ "AWSELBAuthSessionCookie" ]
          signOutUrl: "https://MY_DOMAIN.auth.REGION.amazoncognito.com/logout?\
client_id=ALB_CLIENT_ID&logout_uri=https://STROOM_FQDN/loggedOut"
      openId:
        identityProviderType: EXTERNAL_IDP
        # Cognito's discovery document; supplies the issuer that x-amzn-oidc-data is
        # checked against. Stroom runs no flow of its own, so no clientSecret is needed.
        openIdConfigurationEndpoint: "https://cognito-idp.REGION.amazonaws.com/\
POOL_ID/.well-known/openid-configuration"
        clientId: "ALB_CLIENT_ID"
        # MANDATORY - pins the JWT's 'signer' header to your load balancer(s).
        # Without it, every x-amzn-oidc-data token is rejected. Each value must reach at
        # least the account id; use the full ALB ARN where you know it.
        expectedSignerPrefixes:
          - "arn:aws:elasticloadbalancing:REGION:ACCOUNT_ID:"

expectedSignerPrefixes

The regional AWS endpoint that Stroom fetches verification keys from serves the keys of every load balancer in that region, so the signature alone proves a token came from an ALB, not from your ALB. This setting closes that gap: the signer field in the token’s header, which is the signing load balancer’s ARN, must start with one of the configured values.

It is required — with it unset, every ALB token is rejected, and the log message names this property.

publicKeyUriPattern

The default value fetches keys from https://public-keys.auth.elb.${awsRegion}.amazonaws.com/${keyId}, which is correct for the commercial AWS regions. AWS GovCloud serves the keys from different, S3 hosted endpoints, so GovCloud deployments must override it, e.g.:

        publicKeyUriPattern: "https://s3-us-gov-west-1.amazonaws.com/\
aws-elb-public-keys-prod-us-gov-west-1/${keyId}"

Identity Claims

The claims in x-amzn-oidc-data come from Cognito’s user info endpoint, not from an ID token. The default uniqueIdentityClaim of sub is correct and stable; set userDisplayNameClaim to taste (username and email are usually available).

Logout

AWS documents ending an ALB session as the application’s job: expire the session cookies and send the browser to the IDP’s logout endpoint. The configuration above does exactly that — cookiesToExpire removes the AWSELBAuthSessionCookie shards and signOutUrl sends the browser to Cognito’s /logout.

Two registration details make it work:

  • The logout_uri value must be registered in the Cognito app client as an allowed sign out URL.
  • The page it points at must be matched by a forward rule, not the authenticate rule, or the sign in flow simply restarts and the user never appears to sign out.

Verifying it Works

After deploying, load Stroom in a browser and check, in the developer tools network tab:

  1. You are redirected to the Cognito hosted UI, sign in, and land back at Stroom.
  2. The request to /api/auth/flow/v1/status returns 200 with "authenticated": true and the UI loads.
  3. There is no navigation to .../oauth2/authorize on the Cognito domain after that first sign in — if there is, Stroom is running a second flow and edgeAuthentication.enabled is not set.

On the Stroom side, the log should not contain Redirecting with an AuthenticationRequest to: during normal browsing.

4.2 - NGINX, oauth2-proxy and KeyCloak

Running Stroom behind NGINX with oauth2-proxy authenticating users against KeyCloak (or any Open ID Connect provider).

In this deployment oauth2-proxy is the Open ID Connect Relying Party. NGINX asks it to authorise each request (auth_request); oauth2-proxy completes the code flow against the Identity Provider (IDP) Identity Provider (IDP) An Identity Provider is a system or service that can authenticate a user and assert their identity. Identity providers can support single sign on (SSO), which allows the user to sign in once to the Identity Provider so they are then authenticated to all systems using that IDP.Click to see more details..., holds its session in _oauth2_proxy cookies, and hands back the IDP’s token, which NGINX forwards to Stroom as an Authorization: Bearer header.

Unlike the ALB, nothing here mints its own token: Stroom receives the IDP’s own token and verifies it against the IDP’s published keys, exactly as it would verify a token presented by an API client. That is why this pattern works unchanged with KeyCloak, Cognito or Entra ID behind the proxy.

KeyCloak Setup

Create a realm and a confidential client as described on the KeyCloak page, with one difference: the client’s redirect URI is oauth2-proxy’s callback, https://STROOM_FQDN/oauth2/callback, not Stroom’s.

No second client for Stroom is needed.

Oauth2-proxy Setup

provider = "keycloak-oidc"
oidc_issuer_url = "https://IDP_HOST/realms/REALM"
client_id = "stroom-proxy-client"
client_secret = "THE_CLIENT_SECRET"
redirect_url = "https://STROOM_FQDN/oauth2/callback"
cookie_secret = "RANDOM_32_BYTES_BASE64"

# Hand the IDP's token to NGINX so it can be forwarded to Stroom.
set_authorization_header = true

# Refresh the session before the access token expires, so the forwarded
# token is always live.
cookie_refresh = "4m"

NGINX Setup

The essential shape — authenticate the browser paths, forward the machine paths untouched, and overwrite the Authorization header on everything proxied:

server {
    listen 443 ssl;
    server_name STROOM_FQDN;

    # oauth2-proxy's own endpoints (sign in, callback, sign out)
    location /oauth2/ {
        proxy_pass       http://oauth2-proxy:4180;
        proxy_set_header Host              $host;
        proxy_set_header X-Real-IP         $remote_addr;
        proxy_set_header X-Forwarded-Proto $scheme;
    }

    # Subrequest endpoint used by auth_request
    location = /oauth2/auth {
        internal;
        proxy_pass              http://oauth2-proxy:4180;
        proxy_set_header        Content-Length "";
        proxy_pass_request_body off;
    }

    # Browser facing paths - authenticated
    location / {
        auth_request /oauth2/auth;
        error_page 401 = /oauth2/sign_in;

        # Take the token oauth2-proxy returned and forward it to Stroom.
        # proxy_set_header OVERWRITES any client supplied Authorization header,
        # which is one of the trust prerequisites.
        auth_request_set $auth_token $upstream_http_authorization;
        proxy_set_header Authorization $auth_token;

        proxy_pass       https://stroom-backend:8080/;
        proxy_set_header Host              $host;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header X-Forwarded-Host  $host;
    }

    # Machine paths - no auth_request, Stroom authenticates these itself
    location /datafeed  { proxy_pass https://stroom-backend:8080/datafeed; }
    location /remoting/ { proxy_pass https://stroom-backend:8080/remoting/; }
    location /status    { proxy_pass https://stroom-backend:8080/status; }
}

Stroom Configuration

server:
  applicationConnectors:
    - type: http
      port: 8080
      useForwardedHeaders: true
      maxRequestHeaderSize: 32KiB    # oauth2-proxy chunks its session cookie

appConfig:
  publicUri: "https://STROOM_FQDN"
  security:
    authentication:
      edgeAuthentication:
        enabled: true
        logout:
          cookiesToExpire: [ "_oauth2_proxy" ]
          signOutUrl: "https://STROOM_FQDN/oauth2/sign_out"
      openId:
        identityProviderType: EXTERNAL_IDP
        # The real IDP's discovery document - Stroom verifies the forwarded token
        # against the keys it advertises.
        openIdConfigurationEndpoint: "https://IDP_HOST/realms/REALM/\
.well-known/openid-configuration"
        # oauth2-proxy's client - the forwarded token's audience is this client.
        clientId: "stroom-proxy-client"
        # Leave requiredAccessTokenType unset: oauth2-proxy forwards the ID token.

No clientSecret is needed; Stroom runs no flow of its own.

Logout

The configuration above expires oauth2-proxy’s (chunked) session cookies and sends the browser to /oauth2/sign_out, which ends the proxy session. To also end the KeyCloak session, give oauth2-proxy’s sign out a redirect to KeyCloak’s end session endpoint:

          signOutUrl: "https://STROOM_FQDN/oauth2/sign_out?rd=https%3A%2F%2FIDP_HOST%2Frealms%2FREALM%2Fprotocol%2Fopenid-connect%2Flogout"

(The rd value must be URL encoded and allowed by oauth2-proxy’s whitelist_domains.)

Verifying it Works

  1. Loading Stroom redirects via oauth2-proxy to KeyCloak; after signing in, the UI loads.
  2. The request to /api/auth/flow/v1/status returns 200 with "authenticated": true, and there is no subsequent navigation to KeyCloak’s /auth endpoint.
  3. curl -H "Authorization: Bearer $TOKEN" https://stroom-backend:8080/api/... from inside the network still works — machine access does not traverse the proxy.

5 - Tokens for API use

How to create and use tokens for making API calls.

Creating a User Access Token

If a user wants to use the REST API they will need to create a token for authentication/authorisation in API calls. Any calls to the REST API will have the same permissions that the user has within Stroom.

The following excerpt of shell commands shows how you can get an access/refresh token pair for a user and then later use the refresh token to obtain a new access token. It also shows how you can extract the expiry date/time from a token using jq.

get_jwt_expiry() {
  jq \
    --raw-input \
    --raw-output \
    'split(".") | .[1] | @base64d | fromjson | .exp | todateiso8601' \
    <<< "${1}"
}

# Fetch a new set of tokens (id, access and refresh) for the user
response="$( \
  curl \
    --silent \
    --request POST \
    --header 'Content-Type: application/x-www-form-urlencoded' \
    --data-urlencode 'client_id=admin-cli' \
    --data-urlencode 'grant_type=password' \
    --data-urlencode 'scope=openid' \
    --data-urlencode 'username=jbloggs' \
    --data-urlencode 'password=password' \
    'http://localhost:9999/realms/StroomRealm/protocol/openid-connect/token' )"

# Extract the individual tokens from the response
access_token="$( jq -r '.access_token' <<< "${response}" )"
refresh_token="$( jq -r '.refresh_token' <<< "${response}" )"

# Output the tokens
echo -e "\nAccess token (expiry $( get_jwt_expiry "${access_token}")):\n${access_token}"
echo -e "\nRefresh token (expiry $( get_jwt_expiry "${refresh_token}")):\n${refresh_token}"

# Fetch a new access token using the stored refresh token
response="$( \
  curl \
    --silent \
    --request POST \
    --header 'Content-Type: application/x-www-form-urlencoded' \
    --data-urlencode 'client_id=admin-cli' \
    --data-urlencode 'grant_type=refresh_token' \
    --data-urlencode "refresh_token=${refresh_token}" \
    'http://localhost:9999/realms/StroomRealm/protocol/openid-connect/token' )"

access_token="$( jq -r '.access_token' <<< "${response}" )"
refresh_token="$( jq -r '.refresh_token' <<< "${response}" )"

echo -e "\nNew access token (expiry $( get_jwt_expiry "${access_token}")):\n${access_token}"
echo -e "\nNew refresh token (expiry $( get_jwt_expiry "${refresh_token}")):\n${refresh_token}"

The above example assumes that you have created a user called jbloggs and a client ID admin-cli.

Access tokens typically have a short life (of the order of minutes) while a refresh token will have a much longer life (maybe up to a year). Refreshing the token does not require re-authentication.

Creating a Service Account Token

If you want another system to call one of Stroom’s APIs then it is likely that you will do that using a non-human service account (or processing user account).

Creating a New Client ID

The client system needs to be represented by a Client ID in KeyCloak. To create a new Client ID, assuming the client system is called System X, do the following in the KeyCloak admin UI.

  1. Click Clients in the left pane.
  2. Click Create client.
  3. Set the Client ID to be system-x.
  4. Set the Name to be System X.
  5. Click Next.
  6. Enable Client Authentication.
  7. Enable Service accounts roles.
  8. Click Save.

Open the Credentials tab and copy the Client secret for use later.

To create an access token run the following shell commands:

response="$( \
  curl \
    --silent \
    --request POST \
    --header 'Content-Type: application/x-www-form-urlencoded' \
    --data-urlencode 'client_secret=k0BhYyvt6PHQqwKnnQpbL3KXVFHG0Wa1' \
    --data-urlencode 'client_id=system-x' \
    --data-urlencode 'grant_type=client_credentials' \
    --data-urlencode 'scope=openid' \
    'http://localhost:9999/realms/StroomRealm/protocol/openid-connect/token' )"

access_token="$( jq -r '.access_token' <<< "${response}" )"
refresh_token="$( jq -r '.refresh_token' <<< "${response}" )"

echo -e "\nAccess token:\n${access_token}"

Where client_secret is the Client secret that you copied from KeyCloak earlier.

This access token can be refreshed in the same way as for a user access token, as described above.

Using Access Tokens

Access tokens can be used in calls to Stroom’s REST API or its datafeed API. The process of including the token in a HTTP request is described in API Authentication

6 - Insecure Test Credential

An optional shared secret for wiring Stroom and Stroom-Proxy together in test or demonstration environments.

Stroom offers an optional shared secret that allows Stroom-Proxy, or a test script, to authenticate to Stroom as the internal processing user without an identity provider being involved. It exists so that a test or demonstration stack can function without standing up a real Identity Provider (IDP) Identity Provider (IDP) An Identity Provider is a system or service that can authenticate a user and assert their identity. Identity providers can support single sign on (SSO), which allows the user to sign in once to the Identity Provider so they are then authenticated to all systems using that IDP.Click to see more details....

Enabling the Test Credential

This is not part of the identity provider configuration. The identity provider, normally the internal one, handles all interactive sign in and token authentication as usual. The secret is an addition to that, not a substitute for it.

It is disabled unless both of the following are supplied, as environment variables or as system properties:

Setting Purpose
STROOM_ALLOW_INSECURE_TEST_CREDENTIALS=true An explicit acknowledgement that this is insecure.
STROOM_INSECURE_TEST_CREDENTIAL The shared secret to be matched.

Supplying only the first has no effect other than an error in the logs.

Both are supplied at runtime rather than in a configuration file. This is deliberate. A configuration file copied from a test environment into production cannot carry the secret with it, so a production deployment that never sets these variables cannot be tricked into enabling this.

You choose the secret yourself; Stroom publishes none. A secret shared between systems for convenience is still not a credential to rely on outside test and demonstration use.

While it is enabled, Stroom logs a warning banner at startup, and logs again, at most every five minutes, whenever a request actually authenticates using it.

Configuring Stroom-Proxy to Use the Credential

Set the secret as Stroom-Proxy’s feed status API key, and give it the same value in Stroom’s environment:

  feedStatus:
    apiKey: "THE_VALUE_OF_STROOM_INSECURE_TEST_CREDENTIAL"
  security:
    authentication:
      openId:
        identityProviderType: NO_IDP

A request arriving at Stroom with this value as its bearer token is authenticated as the processing user.

For a secure equivalent, create an API Key API Key API Keys are a form of authentication token that are created within Stroom for use by Stroom-Proxy instances or other clients that want to use Stroom’s API. It is an encrypted string that contains details of the user and the expiration date of the token. Possession of a valid API Key for a user account means that you can do anything that the user can do in the user interface via the API.Click to see more details... in Stroom and use that as the proxy’s feedStatus.apiKey instead, leaving both settings above unset.