Skip to content

Confidential Clients

oauth2 confidential client secret server-side oidc outline integration

Confidential clients are for server-side applications that can securely store a client secret — wikis, dashboards, internal tools, and similar backend services. The third-party app authenticates at the token endpoint using the secret, so there is no need for PKCE.

Use a confidential client when the third-party app:

  • Runs on a server (not in the user’s browser or on a mobile device)
  • Can securely store a client secret (e.g. in environment variables)
  • Examples: Outline, Grafana, GitLab, custom internal tools

Create a confidential client by providing a bcrypt-hashed secret. See Managing Clients for full details on client creation, secret generation, and hashing.

mutation {
insertAuthOauth2Client(object: {
clientSecretHash: "$2b$10$..."
redirectUris: ["https://thirdparty.example.com/auth/callback"]
scopes: ["openid", "profile", "email"]
metadata: { description: "My server-side app" }
}) {
clientId
}
}

Most OIDC-compatible applications need these configuration values:

SettingValue
Client IDThe clientId returned when you created the client (e.g. nhoa_...)
Client SecretThe plaintext secret you saved during creation
Discovery URLhttps://<auth-url>/v1/.well-known/openid-configuration

Many applications support OIDC Discovery — you only need to provide the discovery URL and the app will automatically configure all other endpoints. If the app requires explicit endpoint URLs:

PurposeURL
Authorizationhttps://<auth-url>/v1/oauth2/authorize
Tokenhttps://<auth-url>/v1/oauth2/token
UserInfohttps://<auth-url>/v1/oauth2/userinfo
JWKShttps://<auth-url>/v1/oauth2/jwks

The Outline demo in the Nhost repository shows a full working setup of Outline wiki authenticating through a Nhost project using a confidential client.

The Outline OIDC configuration looks like:

OIDC_CLIENT_ID = "nhoa_a1b2c3d4e5f67890"
OIDC_CLIENT_SECRET = "your-client-secret"
OIDC_AUTH_URI = "https://subdomain.auth.region.nhost.run/v1/oauth2/authorize"
OIDC_TOKEN_URI = "https://subdomain.auth.region.nhost.run/v1/oauth2/token"
OIDC_USERINFO_URI = "https://subdomain.auth.region.nhost.run/v1/oauth2/userinfo"
OIDC_DISPLAY_NAME = "Nhost"
OIDC_SCOPES = "openid profile email"