diff --git a/setup/configuration/idp/auth0.mdx b/setup/configuration/idp/auth0.mdx index ef2e769..1c5e4c6 100644 --- a/setup/configuration/idp/auth0.mdx +++ b/setup/configuration/idp/auth0.mdx @@ -28,8 +28,43 @@ Contact the administrator of the hoop gateway instance to retrieve the `API_URL` - In the **Application Home** > **Settings**, copy the **Domain**. - The issuer url is in the format `https://{YOUR_DOMAIN}` - - - Go to **Applications** > **API** - - Copy the **API Audience** value + + Auth0 returns an opaque access token by default. To receive a JWT access token that Hoop can validate, provide an API audience. + + - Go to **Applications** > **APIs** + - Copy the **API Audience** value (e.g., `https://your-tenant.auth0.com/api/v2/`) - \ No newline at end of file + + +## Configure Hoop Gateway + + + + Go to **Integrations** > **Authentication** and fill in: + - **Auth Method**: OIDC + - **Issuer URL**: `https://{YOUR_DOMAIN}` + - **Client ID**: the Client ID from above + - **Client Secret**: the Client Secret from above + - **Audience** (optional): the API Audience from above + - **Groups Claim**: `groups` (or the custom claim name you configured) + + + ```sh + curl -X PUT {API_URL}/api/serverconfig/auth \ + -H "Api-Key: {API_KEY}" \ + -H "Content-Type: application/json" \ + -d '{ + "auth_method": "oidc", + "provider_name": "auth0", + "oidc_config": { + "issuer_url": "https://{YOUR_DOMAIN}", + "client_id": "{CLIENT_ID}", + "client_secret": "{CLIENT_SECRET}", + "audience": "{API_AUDIENCE}", + "groups_claim": "groups" + }, + "webapp_users_management_status": "active" + }' + ``` + + \ No newline at end of file diff --git a/setup/configuration/idp/aws-cognito.mdx b/setup/configuration/idp/aws-cognito.mdx index 69fdca0..16edfe7 100644 --- a/setup/configuration/idp/aws-cognito.mdx +++ b/setup/configuration/idp/aws-cognito.mdx @@ -46,6 +46,36 @@ Contact the administrator of the hoop gateway instance to retrieve the `API_URL` - The URL is composed by the id of the user pool: `https://cognito-idp..amazonaws.com/` + The Issuer URL is composed from the user pool region and ID: `https://cognito-idp.{aws-region}.amazonaws.com/{user-pool-id}` + +## Configure Hoop Gateway + + + + Go to **Integrations** > **Authentication** and fill in: + - **Auth Method**: OIDC + - **Issuer URL**: `https://cognito-idp.{aws-region}.amazonaws.com/{user-pool-id}` + - **Client ID**: the Client ID from above + - **Client Secret**: the Client Secret from above + + + ```sh + curl -X PUT {API_URL}/api/serverconfig/auth \ + -H "Api-Key: {API_KEY}" \ + -H "Content-Type: application/json" \ + -d '{ + "auth_method": "oidc", + "provider_name": "aws-cognito", + "oidc_config": { + "issuer_url": "https://cognito-idp.{AWS_REGION}.amazonaws.com/{USER_POOL_ID}", + "client_id": "{CLIENT_ID}", + "client_secret": "{CLIENT_SECRET}", + "groups_claim": "groups" + }, + "webapp_users_management_status": "active" + }' + ``` + + diff --git a/setup/configuration/idp/azure.mdx b/setup/configuration/idp/azure.mdx index 7a435ca..5a65d1e 100644 --- a/setup/configuration/idp/azure.mdx +++ b/setup/configuration/idp/azure.mdx @@ -34,18 +34,48 @@ Contact the administrator of the hoop gateway instance to retrieve the API_URL a - Copy the Secret Value. This is the Client Secret - The Issuer URL - - Go to App registration > `{AppName}` > Overview - - Copy the tenant ID and use as the value below - - https://login.microsoftonline.com/{tenant_id}/v2.0 - - The Custom Scopes - - Use the Client ID to compose the Custom Scopes value - - `{CLIENT_ID}/.default` + The Issuer URL: + - Go to **App registration** > `{AppName}` > **Overview** + - Copy the **Directory (tenant) ID** and compose the URL: `https://login.microsoftonline.com/{tenant_id}/v2.0` + The Custom Scopes value: + - Use the Client ID to compose it: `{CLIENT_ID}/.default` +## Configure Hoop Gateway + + + + Go to **Integrations** > **Authentication** and fill in: + - **Auth Method**: OIDC + - **Issuer URL**: `https://login.microsoftonline.com/{tenant_id}/v2.0` + - **Client ID**: the Application (client) ID from above + - **Client Secret**: the Secret Value from above + - **Scopes**: `{CLIENT_ID}/.default` + - **Groups Claim**: `groups` + + + ```sh + curl -X PUT {API_URL}/api/serverconfig/auth \ + -H "Api-Key: {API_KEY}" \ + -H "Content-Type: application/json" \ + -d '{ + "auth_method": "oidc", + "provider_name": "azure", + "oidc_config": { + "issuer_url": "https://login.microsoftonline.com/{TENANT_ID}/v2.0", + "client_id": "{CLIENT_ID}", + "client_secret": "{CLIENT_SECRET}", + "scopes": ["{CLIENT_ID}/.default"], + "groups_claim": "groups" + }, + "webapp_users_management_status": "active" + }' + ``` + + + ## Configuring Groups Claims The integration relies on groups propagated in the `id_token`. By default, Azure Entra ID propagates them in the `groups` claims. @@ -67,9 +97,7 @@ By default, groups are propagate with their object ids. It may be cumbersome to See the section below to propagate them with their display name instead. - When you configure groups to sync, you'll lose the admin access on the next sign in. - To prevent this issue, set the configuration `ADMIN_USERNAME` on your gateway to change the role of the admin user with a group associated with your application. - The name of the admin group depends on whether you propagate the groups as object IDs or as group names (see below). + When you configure groups to sync, you'll lose admin access on the next sign-in unless your Azure group maps to the configured admin role name. Update the **Admin Role Name** in **Integrations** > **Authentication** to match the Azure group name or object ID you want as admin before signing in again. The group identifier depends on whether you propagate groups as object IDs or display names (see below). ### Propagating Groups as Names @@ -145,46 +173,51 @@ It is possible to access hoop by issuing access tokens using the Oauth2 Client C ### Creating a Service Account -```sh -hoop admin create serviceaccount \ - --name "My Service Account" \ - --groups admin -``` - - To obtain the Object ID of the application navigate to: Azure Portal > Microsoft Entra ID > Enterprise Applications + To obtain the Object ID of the application navigate to: **Azure Portal** > **Microsoft Entra ID** > **Enterprise Applications**. -### Creating an Access Token +```sh +curl -X POST {API_URL}/api/serviceaccounts \ + -H "Api-Key: {API_KEY}" \ + -H "Content-Type: application/json" \ + -d '{ + "subject": "", + "name": "My Service Account", + "status": "active", + "groups": ["admin"] + }' +``` -1. Go to App Registrations > Certificate & Secrets > New Client Secret +### Creating an Access Token -Copy the secret value and use in the command below as the attribute for `` +1. Go to **App Registrations** > **Certificate & Secrets** > **New Client Secret** and copy the secret value. -2. Generate an access token +2. Generate an access token from Azure: ```sh -curl -XPOST -H "Content-Type: application/x-www-form-urlencoded" \ - -d client_id= \ - -d scope=/.default \ - -d client_secret= \ - -d grant_type=client_credentials \ - https://login.microsoftonline.com//oauth2/v2.0/token +curl -X POST \ + -H "Content-Type: application/x-www-form-urlencoded" \ + -d "client_id=" \ + -d "scope=/.default" \ + -d "client_secret=" \ + -d "grant_type=client_credentials" \ + https://login.microsoftonline.com//oauth2/v2.0/token ``` -- APP_CLIENT_ID: the client id of the application -- APP_CLIENT_SECRET: the client secret generated in the step 1 -- TENANT_ID: the tenant id of you app instance +- `APP_CLIENT_ID`: the client ID of the application +- `APP_CLIENT_SECRET`: the client secret from step 1 +- `TENANT_ID`: the tenant ID of your Azure instance For more information, [see this guide](https://learn.microsoft.com/en-us/entra/identity-platform/v2-oauth2-client-creds-grant-flow#get-a-token). -Access the API +3. Verify access with the Hoop API: ```sh -export HOOP_TOKEN=eyJ0eXAiOiJKV1QiLCJhb...5Z3Be-kkXkAnAA-zIweYuqEUDA -hoop admin get userinfo +curl {API_URL}/api/userinfo \ + -H "Authorization: Bearer " ``` - In case of receiving access denied (401), make sure that the subject of the access token matches the subject provided when creating the service account (usually matches the object id of the application) + If you receive a 401, ensure the `subject` of the access token (the application's Object ID) matches the `subject` used when creating the service account. diff --git a/setup/configuration/idp/get-started.mdx b/setup/configuration/idp/get-started.mdx index 530b38c..7a1cf60 100644 --- a/setup/configuration/idp/get-started.mdx +++ b/setup/configuration/idp/get-started.mdx @@ -3,7 +3,7 @@ title: "Overview" description: "Integrate with your own Identity Provider" --- -We support a variety of Identity Providers to authenticate users in hoop.dev. In this guide you will find the IDPs we had success integrating with but as due to how we integrate with them using OIDC standards, you can try to integrate with any OIDC compliant IDP. +We support a variety of Identity Providers to authenticate users in hoop.dev. Integration uses the **OIDC (OpenID Connect)** or **SAML 2.0** protocols. Any OIDC-compliant identity provider should work; the guides below cover providers that have been validated. @@ -16,68 +16,156 @@ We support a variety of Identity Providers to authenticate users in hoop.dev. In ## Users -Users are active and assigned to the default organization when they signup. A user could be set to an inactive state preventing it from accessing the platform, however it’s recommended to manage the state of users in the identity provider. +Users are active and assigned to the default organization when they sign up. A user can be set to an inactive state to prevent access, however it is recommended to manage user state in the identity provider rather than in hoop.dev. - The `sub` claim is used as the main identifier of the user in the platform. -- The profile of the user is derived from the id_token claims `email` and `name`. +- The user's profile is derived from the `email` and `name` claims in the ID token. -When a user authenticates for the first time, it performs an automatic signup that persist the profile claims along with it’s unique identifier. +When a user authenticates for the first time, hoop.dev performs an automatic signup that persists the profile claims along with their unique identifier. ## Groups -Groups allows defining who may access or interact with certain resources. +Groups control who may access or interact with certain resources. -- For **connection** resources it’s possible to define which groups has access to a specific connection, this is enforced when the **Access Control feature** is enabled. -- For **access requests**, it's possible to define which groups are allowed to approve an execution, this is enforced when the **Access Requests feature** is enabled. +- For **connection** resources, groups define which users have access to a connection. This is enforced when the **Access Control** feature is enabled. +- For **access requests**, groups define which users are allowed to approve an execution. This is enforced when the **Access Requests** feature is enabled. -This resource could be managed manually via Webapp or propagated by the identity provider via ID Token. In this mode, groups are sync when a user performs a login. + Groups can be managed manually via the Webapp, or propagated automatically by the identity provider via the ID token. When propagated by the IdP, groups are synced each time a user signs in. ## Roles -- The **admin** group is a special role that grants full access to all resources +- The **admin** group grants full access to all resources. Assign this to users responsible for managing the Gateway. +- The **auditor** group grants read-only access to session resources. +- All other users are **regular** users who can access their own resources and interact with connections. -This role should be granted to users that are responsible for managing the Gateway. All other users are regular, meaning that they can access their own resources and interacting with connections. +The default role names (`admin` and `auditor`) can be changed to match the group names in your identity provider via **Integrations** > **Authentication** in the Webapp, or via the `admin_role_name` / `auditor_role_name` fields in the API. -- The **auditor** group grants the auditor role that gives read only access to session resources + + Role name changes take effect on the next sign-in. If you change the admin role name and no user belonging to the new group has signed in yet, you may lose admin access. Update the role name before removing yourself from the previous admin group. + -## Configuration Page +## Configuration - This feature is available beginning with version `1.38.12` + Configuring the identity provider via the Webapp or API is available beginning with version `1.38.12`. -Users are now able to configure the identity provider directly from the Webapp. + + + Go to **Integrations** > **Authentication** to configure the identity provider. + + + + + + + After saving, the identity provider reloads automatically with the new settings. Any `IDP_*` environment variables will be ignored once a configuration is saved here. + + + + Use `PUT {API_URL}/api/serverconfig/auth` authenticated with an admin `Api-Key` header. + + ### OIDC / OAuth 2.0 + + | Field | Required | Description | + |-------|----------|-------------| + | `auth_method` | yes | Set to `"oidc"` | + | `oidc_config.issuer_url` | yes | The provider's OIDC discovery base URL | + | `oidc_config.client_id` | yes | OAuth2 client ID | + | `oidc_config.client_secret` | yes | OAuth2 client secret | + | `oidc_config.scopes` | no | Additional scopes to request. Defaults are `openid`, `profile`, and `email` | + | `oidc_config.audience` | no | OAuth2 audience. Required for providers that return opaque access tokens by default (e.g. Auth0) | + | `oidc_config.groups_claim` | no | ID token claim used to read group membership. Default: `groups` | + | `admin_role_name` | no | Group name mapped to the admin role. Default: `admin` | + | `auditor_role_name` | no | Group name mapped to the auditor role. Default: `auditor` | + | `webapp_users_management_status` | yes | `"active"` enables user management in the Webapp; `"inactive"` disables it | + + ```sh + curl -X PUT {API_URL}/api/serverconfig/auth \ + -H "Api-Key: {API_KEY}" \ + -H "Content-Type: application/json" \ + -d '{ + "auth_method": "oidc", + "oidc_config": { + "issuer_url": "https://your-idp.example.com", + "client_id": "your-client-id", + "client_secret": "your-client-secret", + "groups_claim": "groups" + }, + "webapp_users_management_status": "active", + "admin_role_name": "admin", + "auditor_role_name": "auditor" + }' + ``` + + ### SAML 2.0 + + | Field | Required | Description | + |-------|----------|-------------| + | `auth_method` | yes | Set to `"saml"` | + | `saml_config.idp_metadata_url` | yes | URL to the IdP's SAML metadata XML | + | `saml_config.groups_claim` | no | SAML assertion attribute used to read group membership. Default: `groups` | + | `webapp_users_management_status` | yes | `"active"` or `"inactive"` | + + ```sh + curl -X PUT {API_URL}/api/serverconfig/auth \ + -H "Api-Key: {API_KEY}" \ + -H "Content-Type: application/json" \ + -d '{ + "auth_method": "saml", + "saml_config": { + "idp_metadata_url": "https://your-idp.example.com/saml/metadata", + "groups_claim": "groups" + }, + "webapp_users_management_status": "active" + }' + ``` + + Configure your identity provider with these service provider (SP) endpoints: + + | Endpoint | Value | + |----------|-------| + | ACS URL / Callback | `{API_URL}/api/saml/callback` | + | Entity ID / Audience URI | `{API_URL}/saml/acs` | + + - - - +## Troubleshooting - - After the configuration is saved, the identity provider will be automatically reloaded with the new settings. - The environment variables will not be considered as part of the configuration. - +### Groups not syncing -## Troubleshooting +- Confirm the `groups_claim` field matches the exact claim name your provider includes in the ID token. You can inspect the claim being received by checking the gateway logs when a user signs in. +- Ensure the claim is configured to be emitted in the **ID token** (not just the access token). Refer to your provider's guide for claim configuration. +- Some providers (e.g. Okta) only include the groups claim when a user belongs to at least one group. Ensure every user has at least one group assigned. + +### Login fails or callback errors + +- Verify the redirect URI configured in the identity provider exactly matches `{API_URL}/api/callback` (no trailing slash, correct scheme). +- For SAML, confirm the ACS URL is set to `{API_URL}/api/saml/callback` and the Entity ID matches `{API_URL}/saml/acs`. -The IDP configuration experience could lock yourself out of the application if not configured correctly. +### Access token validation fails (opaque tokens) -To wipe all the configuration, connect in the Hoop Postgres database and the delete the following row: +Some providers (e.g. Okta with certain authorization server configurations) issue opaque access tokens that cannot be validated directly. Append `?_userinfo=1` to the Issuer URL to instruct the gateway to authenticate via the userinfo endpoint instead: + +``` +https://your-org.okta.com/oauth2/default?_userinfo=1 +``` + +### Locked out after misconfiguration + +If an incorrect configuration prevents any user from signing in, connect to the Hoop PostgreSQL database and clear the stored configuration: ```sql --- clear all configuration +-- Remove all IDP configuration (gateway will fall back to environment variables or local auth) DELETE FROM private.authconfig WHERE org_id = (SELECT id FROM private.orgs); ``` -To update a single configuration: +To update a single field without a full reset: ```sql UPDATE private.authconfig SET admin_role_name = 'my-new-admin-role-group' WHERE org_id = (SELECT id FROM private.orgs); ``` - - - In the upcoming releases we will improve this experience to avoid this situation. - diff --git a/setup/configuration/idp/google.mdx b/setup/configuration/idp/google.mdx index f330b79..04d91e9 100644 --- a/setup/configuration/idp/google.mdx +++ b/setup/configuration/idp/google.mdx @@ -33,6 +33,36 @@ Contact the administrator of the hoop gateway instance to retrieve the `API_URL` +## Configure Hoop Gateway + + + + Go to **Integrations** > **Authentication** and fill in: + - **Auth Method**: OIDC + - **Issuer URL**: `https://accounts.google.com` + - **Client ID**: the Client ID from above + - **Client Secret**: the Client Secret from above + + + ```sh + curl -X PUT {API_URL}/api/serverconfig/auth \ + -H "Api-Key: {API_KEY}" \ + -H "Content-Type: application/json" \ + -d '{ + "auth_method": "oidc", + "provider_name": "google", + "oidc_config": { + "issuer_url": "https://accounts.google.com", + "client_id": "{CLIENT_ID}", + "client_secret": "{CLIENT_SECRET}", + "groups_claim": "groups" + }, + "webapp_users_management_status": "active" + }' + ``` + + + ## Configuring Groups Groups are synchronized by performing a request to the [Cloud Identity API](https://cloud.google.com/identity/docs/reference/rest/v1/groups.memberships/searchDirectGroups) as a best effort operation. @@ -42,20 +72,18 @@ Groups are synchronized by performing a request to the [Cloud Identity API](http - - Configure the gateway with the env **IDP_CUSTOM_SCOPES** + + Add the Cloud Identity scope to the gateway configuration. In **Integrations** > **Authentication**, add the following to the **Scopes** field: - `https://www.googleapis.com/auth/cloud-identity.groups.readonly` + Or via API, include it in the `scopes` array of the `oidc_config`. + Users will need to provide consent for the following access permissions when first logging in to enable proper group synchronization. - - - Restart the gateway after applying these changes. - @@ -65,6 +93,5 @@ Groups are synchronized by performing a request to the [Cloud Identity API](http - When configuring group synchronization, admin access may be revoked upon your next sign-in. - To maintain administrative privileges, set the `ADMIN_USERNAME` configuration parameter to a Google Workspace group that you want to map as admin on Hoop. + When configuring group synchronization, admin access may be revoked upon your next sign-in. To maintain administrative privileges, update the **Admin Role Name** in **Integrations** > **Authentication** to match a Google Workspace group you belong to before signing in again. diff --git a/setup/configuration/idp/jumpcloud.mdx b/setup/configuration/idp/jumpcloud.mdx index 6cd3c4c..f8d2639 100644 --- a/setup/configuration/idp/jumpcloud.mdx +++ b/setup/configuration/idp/jumpcloud.mdx @@ -2,10 +2,6 @@ title: "JumpCloud" --- - - JumpCloud doesn’t emit JWT as access token, thus the gateway validates if a client is authenticated performing an http request to the userinfo endpoint (oidc spec). - - ## Requirements - An [admin account in JumpCloud](https://console.jumpcloud.com) @@ -43,6 +39,41 @@ Contact the administrator of the hoop gateway instance to retrieve the `API_URL` +## Configure Hoop Gateway + + + JumpCloud validates authentication via the userinfo endpoint rather than JWT token validation. No special configuration is required for this — it is handled automatically. + + + + + Go to **Integrations** > **Authentication** and fill in: + - **Auth Method**: OIDC + - **Issuer URL**: `https://oauth.id.jumpcloud.com/` + - **Client ID**: the Client ID from above + - **Client Secret**: the Client Secret from above + - **Groups Claim**: `https://app.hoop.dev/groups` (if groups attribute was configured) + + + ```sh + curl -X PUT {API_URL}/api/serverconfig/auth \ + -H "Api-Key: {API_KEY}" \ + -H "Content-Type: application/json" \ + -d '{ + "auth_method": "oidc", + "provider_name": "jumpcloud", + "oidc_config": { + "issuer_url": "https://oauth.id.jumpcloud.com/", + "client_id": "{CLIENT_ID}", + "client_secret": "{CLIENT_SECRET}", + "groups_claim": "https://app.hoop.dev/groups" + }, + "webapp_users_management_status": "active" + }' + ``` + + + ## Associating User Groups To propagate groups to Hoop, create a new group diff --git a/setup/configuration/idp/okta.mdx b/setup/configuration/idp/okta.mdx index 05e8e3e..892574f 100644 --- a/setup/configuration/idp/okta.mdx +++ b/setup/configuration/idp/okta.mdx @@ -28,13 +28,44 @@ Contact the administrator of the hoop gateway instance to retrieve the `API_URL` - The Issuer URI depends on the authorization server being used. Refer to [this documentation](https://developer.okta.com/docs/concepts/auth-servers/#available-authorization-server-types). + - If Okta does not allow external applications to validate access tokens, add the query string option `_userinfo=1` when configuring the Gateway. It indicates to use the user info endpoint. - The _userinfo value is removed when used to exchange information with the identity provider. + If Okta does not allow external applications to validate access tokens, append `?_userinfo=1` to the Issuer URL (e.g., `https://your-org.okta.com/oauth2/default?_userinfo=1`). This tells the gateway to authenticate using the userinfo endpoint instead of validating the token directly. +## Configure Hoop Gateway + + + + Go to **Integrations** > **Authentication** and fill in: + - **Auth Method**: OIDC + - **Issuer URL**: your Okta authorization server URI + - **Client ID**: the Client ID from above + - **Client Secret**: the Client Secret from above + - **Groups Claim**: `groups` + + + ```sh + curl -X PUT {API_URL}/api/serverconfig/auth \ + -H "Api-Key: {API_KEY}" \ + -H "Content-Type: application/json" \ + -d '{ + "auth_method": "oidc", + "provider_name": "okta", + "oidc_config": { + "issuer_url": "https://{YOUR_OKTA_DOMAIN}/oauth2/default", + "client_id": "{CLIENT_ID}", + "client_secret": "{CLIENT_SECRET}", + "groups_claim": "groups" + }, + "webapp_users_management_status": "active" + }' + ``` + + + ## Configuring Groups Explains how to configure groups claim to propagate when users sign in. @@ -78,9 +109,8 @@ Explains how to configure groups claim to propagate when users sign in. - - The Hoop gateway requires proper configuration to correctly map claim names for synchronization. - For detailed instructions, please consult the [OAuth2/OIDC Authentication Documentation](/setup/configuration/env-vars) + + Ensure the **Groups Claim** field in **Integrations** > **Authentication** is set to `groups` to match the claim name configured above. This is the default value and usually requires no change.