Connect an application with SSO
Use this guide when an application speaks OpenID Connect and you want FerrisKey to handle sign-in.
By the end you will have:
- One FerrisKey realm dedicated to the application or organization
- One OpenID Connect client
- A client ID and client secret
- The redirect URI registered in FerrisKey
- The issuer URL and discovery endpoint your application needs
Before you start
Before opening FerrisKey, find these values in the application you want to connect:
| Value | Example |
|---|---|
| Application URL | https://vault.example.com |
| Callback or redirect URI | https://vault.example.com/identity/connect/oidc-signin |
| Required scopes | openid profile email |
Use the application's exact callback URL
The redirect URI must match what the application sends during login. If the application says the callback is /identity/connect/oidc-signin, do not replace it with the application homepage.
Example values
The walkthrough uses these values. Replace them with your own domains and realm name.
| Setting | Value |
|---|---|
| FerrisKey URL | https://sso.example.com |
| Realm | home |
| Client ID | vaultwarden |
| Application URL | https://vault.example.com |
| Redirect URI | https://vault.example.com/identity/connect/oidc-signin |
| Scopes | openid profile email |
Create or select the realm
A realm keeps users, clients, roles, and scopes together. Avoid using master for applications.
Open the realm selector
Click the realm name in the top bar, next to the FerrisKey logo. Pick the realm that will own this application, or Create realm if you need a new one. The selector is searchable, which matters once a deployment holds more than a handful.

Stay in the application realm
After switching, check the realm indicator before creating the client. The client will be created in the realm currently selected in the dashboard.
Create the client
The client is the application entry in FerrisKey. It tells FerrisKey which app is asking users to sign in.
Open Clients
In the sidebar, click Clients, then New client.


The banner at the top of that list is worth reading before you add anything: it names every client that has no redirect URI, because the authorization code flow cannot work without one.
Choose the protocol
Creation starts by asking which protocol the application speaks: OpenID Connect for anything token-based, or SAML 2.0 for applications that speak nothing else.


This choice is final
It decides how the application signs its users in and cannot be changed after creation. An application that later moves from SAML to OIDC needs a new client, not an edited one. See Authentication for what each protocol gives you.
Fill the client details
Use a stable client ID. In this example:
| Field | Value |
|---|---|
| Client ID | vaultwarden |
| Name | Vaultwarden |
| Client enabled | Enabled |
| Client authentication | Confidential |
Client authentication is a choice between Confidential and Public, and it is also final. Pick Confidential for a server-side application that can hold a secret; FerrisKey then generates one. Pick Public for an SPA, a mobile app or a CLI, where a secret would end up in the user’s hands and PKCE carries the protection instead.
Leave both capability switches off for browser SSO: Direct access grants is the deprecated password grant, and the device authorization grant is for browserless clients.
The client is created with PKCE required, which means the application has to send an S256 code challenge with its authorization request. Most OIDC libraries do so by default. The Require PKCE switch is under Capability config in the client’s Settings tab.

Configure the redirect URI
The redirect URI is where FerrisKey sends the browser after a successful login.
Open the client settings
Open the client you just created and stay on the Settings tab.
Add the redirect URI
Scroll to the Access section and add the exact callback URL from your application. Every entry is saved as you add it, so there is no separate save button for this list.
For the example:
https://vault.example.com/identity/connect/oidc-signin

FerrisKey compares the callback with the entries character for character. Only an entry written ^...$ is read as a regular expression, so keep literal addresses unless the callback really varies.
Two neighbours in the same area matter as much as the redirect URI:
- Web origins are the origins this application may call FerrisKey from in a browser. The
+button derives them from the redirect URIs you just entered, but only from literal ones: regex patterns are skipped. Removing an origin takes a few minutes to clear browser preflight caches, and up to 30 seconds to propagate to the other API replicas. - Post-logout redirect URIs, under Logout, are where the user can land once the session closes. FerrisKey redirects there only when the logout request names the address and identifies the client, and the address must match an entry exactly. Without a redirect, logout answers with an empty
204and the user stays on the page that sent the request: FerrisKey shows no page of its own.
The same Logout section holds the Back-channel logout URL, where FerrisKey tells the application’s backend that a session ended. See back-channel logout.
Copy the client secret
Open Credentials
Open the client’s Credentials tab.
Copy the secret
The secret is masked. Click Reveal to read it, then copy it into the application’s OIDC configuration and treat it like a password.


Revealing a secret is recorded as a security event, client_secret_viewed in SeaWatch. That is intentional: an unexplained reveal is visible in the audit trail.
A leaked secret cannot be rotated through the API yet
Rotating a client secret is not exposed by the administration API at this version, as the Credentials tab states. So if a secret is pasted into a public issue, a log, a screenshot or a repository, there is no rotate call to make.
Until it ships, the containment path is to create a replacement client, move the application over, and delete the compromised one. Plan for that being slower than a rotation, and treat client secrets accordingly: keep them in a secret manager, never in a screenshot.
Check the client scopes
Most OIDC applications need openid, profile, and email.
Open Client Scopes
Open the client’s Client Scopes tab.
Confirm required scopes
Each assigned scope carries a default or optional switch. Make sure these three are on default, which means every token gets them without the application asking:
openidprofileemail
A client created now already has openid, profile, email, roles and organization as default scopes, so this step is mostly a check. address, phone and offline_access exist in the realm but are not attached to a new client. Add one as optional if the application needs it, and it applies only when a request names it in its scope parameter.


The Evaluate sub-tab next to the assigned list answers the question this step is really about: it shows the claims this client would receive, without you having to run a login first.
Configure the application
Paste these values into the application.
| Application setting | FerrisKey value |
|---|---|
| Issuer / Authority | https://sso.example.com/realms/home |
| Discovery endpoint | https://sso.example.com/realms/home/.well-known/openid-configuration |
| Client ID | vaultwarden |
| Client Secret | The value from the Credentials tab |
| Scopes | openid profile email |
| Redirect URI | https://vault.example.com/identity/connect/oidc-signin |
What the discovery endpoint does
The discovery endpoint is where an OpenID Connect application learns how to talk to FerrisKey.
https://sso.example.com/realms/home/.well-known/openid-configuration
When the application opens that URL, FerrisKey returns a JSON document with the realm’s OIDC metadata. That document tells the application:
- Where to redirect users when they click “Sign in”
- Where to exchange the authorization code for tokens
- Which issuer value to expect in tokens
- Where to fetch the public keys used to verify token signatures
- Which scopes, grants and client authentication methods are supported
That is why so many applications only ask for an issuer, an authority, or a discovery URL, instead of making you fill in every endpoint by hand.
Authority or discovery endpoint
Some applications ask for the issuer or authority URL, others for the discovery endpoint. When it asks for the authority, give it the realm URL without the /.well-known/openid-configuration suffix.
Test the login
- Open the application in a private browser window.
- Click the SSO or OpenID Connect login button.
- Confirm that the browser redirects to FerrisKey.
- Sign in with a user from the same realm.
- Confirm that FerrisKey redirects back to the application.
- Sign out of the application. If it calls the FerrisKey logout endpoint, the SSO session ends, and the next sign-in asks for credentials again.
If the user signs in but the application says the account is not allowed, look at the application’s own signup, domain, group, or role rules. FerrisKey authenticated the user; the application still gets to decide whether that user is welcome.
Troubleshooting
Invalid redirect URI
FerrisKey does not send the browser to the address the application asked for. It lands on the FerrisKey login page with an error message instead.
Check that the redirect URI in the client settings exactly matches the callback URL sent by the application. Compare the scheme, domain, path, trailing slash, and port. Only an entry written ^...$ is read as a pattern.
Discovery endpoint does not load
Open this URL from your browser and from the application container or server:
https://sso.example.com/realms/home/.well-known/openid-configuration
It should return a JSON document. If it does not, check the FerrisKey public URL, reverse proxy, TLS certificate, and realm name.
Issuer mismatch
Some applications validate that the configured authority equals the issuer field returned by the discovery endpoint.
Open the discovery endpoint and copy the issuer value. Use that exact value as the application’s issuer or authority.
FerrisKey builds the issuer from the Host and X-Forwarded-Proto headers of each request. If the issuer shows an internal host name or http:// while users reach FerrisKey over https, the reverse proxy is not forwarding those headers.
Client authentication failed
The application reaches FerrisKey but token exchange fails.
Check:
- The client is enabled
- Client Authentication is enabled for confidential applications
- The application uses the current client secret
- There are no extra spaces around the copied secret
- A secret containing
+or%is percent-encoded when it travels in an HTTP Basic header
FerrisKey answers invalid_client with a 401 whether the client is unknown, disabled or sent a wrong secret. After 10 failed attempts within a minute from the same address for the same client, it answers 429 with Retry-After: 60 until the delay passes.
PKCE is required
The authorization request fails with invalid_request and a message about PKCE. The client requires an S256 code challenge, and the application did not send one. Make the application send code_challenge with code_challenge_method=S256. Only if it cannot, switch Require PKCE off in the client’s capability config.
The application gets login_required or consent_required
An authorization request with prompt=none never shows a page. FerrisKey sends the browser back with login_required when no SSO session exists, interaction_required when the account still owes a step, and consent_required when the consent screen would have to appear. The application has to fall back to an interactive request. See the authorization request.
Missing email or profile data
The login succeeds but the application cannot create or match the account.
Check that openid, profile, and email are assigned as default client scopes. Also check that the FerrisKey user has an email address.
The application asks for password grant
Prefer authorization code flow when the application supports it. Only enable Direct Access Grants if the application explicitly requires grant_type=password and you trust it to handle user passwords directly.