Stronghold can act as an OIDC provider (OpenID Provider) for applications that support OpenID Connect login. A user logs in to Stronghold with any configured auth method, and the application receives an ID token with Stronghold entity data: name, email address, groups.

Goal

Connect an internal application (Grafana in the example) to the Stronghold OIDC provider so that only members of the grafana-users group can log in and the application receives the user’s email address and group list.

Prerequisites

Before you start, prepare the following:

  • A Stronghold token with permissions on identity/*.
  • A configured auth method for users (for example, OIDC through Dex in DP, or userpass).
  • An Identity group grafana-users that contains user entities, and email metadata on the entities.
  • An external Stronghold address reachable by user browsers and the application: https://stronghold.example.com in the examples.

Entities, groups, and aliases are described in Identity.

Step 1. Create a signing key

Create the apps key that signs ID tokens:

d8 stronghold write identity/oidc/key/apps algorithm=RS256 rotation_period=24h verification_ttl=24h

The key rotates automatically once a day, and the previous public part stays available for signature verification for verification_ttl.

Step 2. Restrict who can log in

An assignment defines the entities and groups allowed to log in through the client application:

GROUP_ID=$(d8 stronghold read -field=id identity/group/name/grafana-users)

d8 stronghold write identity/oidc/assignment/grafana-users group_ids="$GROUP_ID"

The built-in allow_all assignment allows all entities to log in: do not use it for production applications.

Step 3. Create scopes

Scopes add claims to the ID token based on a template. The template syntax is the same as for templated policies.

d8 stronghold write identity/oidc/scope/email description="User email address" template='{"email": {{identity.entity.metadata.email}}}'

d8 stronghold write identity/oidc/scope/groups description="User groups" template='{"groups": {{identity.entity.groups.names}}}'

The template parameter accepts both a JSON string and a base64-encoded value.

Step 4. Create a client application

Create the grafana client with the application redirect URI, the assignment and the signing key:

d8 stronghold write identity/oidc/client/grafana redirect_uris="https://grafana.example.com/login/generic_oauth" assignments="grafana-users" key="apps" id_token_ttl=30m access_token_ttl=1h

Allow the client to use the apps key:

CLIENT_ID=$(d8 stronghold read -field=client_id identity/oidc/client/grafana)

d8 stronghold write identity/oidc/key/apps allowed_client_ids="$CLIENT_ID"

Step 5. Create a provider

Create the internal provider and allow the client to use it:

d8 stronghold write identity/oidc/provider/internal issuer="https://stronghold.example.com" allowed_client_ids="$CLIENT_ID" scopes_supported="email,groups"

Get the parameters for configuring the application:

d8 stronghold read identity/oidc/client/grafana
curl -s https://stronghold.example.com/v1/identity/oidc/provider/internal/.well-known/openid-configuration | jq

From the responses, you need client_id, client_secret, issuer, authorization_endpoint, token_endpoint, and userinfo_endpoint.

Step 6. Configure the application

An example Grafana configuration (the auth.generic_oauth section in grafana.ini):

[auth.generic_oauth]
enabled = true
name = Stronghold
client_id = <CLIENT_ID>
client_secret = <CLIENT_SECRET>
scopes = openid email groups
auth_url = https://stronghold.example.com/ui/stronghold/identity/oidc/provider/internal/authorize
token_url = https://stronghold.example.com/v1/identity/oidc/provider/internal/token
api_url = https://stronghold.example.com/v1/identity/oidc/provider/internal/userinfo
email_attribute_path = email
groups_attribute_path = groups

<CLIENT_ID> and <CLIENT_SECRET> are the client_id and client_secret values from the identity/oidc/client/grafana response.

Store client_secret in Stronghold and deliver it to the application like other secrets, for example with Stronghold Agent or the Kubernetes integration.

Verification

Check the result:

  1. Open the application and choose to log in with Stronghold. The browser redirects you to the Stronghold login page and, after login, back to the application.

  2. Log in as a user who is not in the grafana-users group: login must be rejected.

  3. Check the ID token contents in the application log or decode it: it must contain iss, aud (equal to client_id), email, and groups.

  4. Check that the public keys are available:

    curl -s https://stronghold.example.com/v1/identity/oidc/provider/internal/.well-known/keys | jq '.keys[].kid'

Cleanup

Delete the objects created in this guide:

d8 stronghold delete identity/oidc/provider/internal
d8 stronghold delete identity/oidc/client/grafana
d8 stronghold delete identity/oidc/scope/email
d8 stronghold delete identity/oidc/scope/groups
d8 stronghold delete identity/oidc/assignment/grafana-users
d8 stronghold delete identity/oidc/key/apps

Additional resources