<a id="okta"></a>

# Okta

<a id="backend-classes"></a>

## Backend classes

For Django, choose from these class paths for `AUTHENTICATION_BACKENDS`.
For other integrations, use the same class paths in the
framework-specific backend setting.

| Backend name         | Class path                                                  |
|----------------------|-------------------------------------------------------------|
| `okta-oauth2`        | `social_core.backends.okta.OktaOAuth2`                      |
| `okta-openidconnect` | `social_core.backends.okta_openidconnect.OktaOpenIdConnect` |

This section describes how to setup the different services provided by Okta.

<a id="okta-oauth2"></a>

## Okta OAuth2

<a id="idp-setup"></a>

### IdP Setup

To configure Okta for OAuth2:

1. Log into your Okta Admin Console
2. Navigate to **Applications** > **Create App Integration**
3. Select **OIDC - OpenID Connect** and **Web Application**
4. Set the **Sign-in redirect URI** to:
   ```default
   https://your-domain.com/complete/okta-oauth2/
   ```
5. Save and note the **Client ID**, **Client Secret**, and **Okta domain** (e.g., `https://dev-123456.okta.com`)

#### IMPORTANT
Do NOT use the `/oauth2/default` endpoint for Okta authentication.

<a id="application-configuration"></a>

### Application Configuration

Fill `Client ID`, `Client Secret` and `API URL (e.g.
https://dev-123456.okta.com/oauth2)` settings with the values from the IdP setup above:

```default
SOCIAL_AUTH_OKTA_OAUTH2_KEY = ''
SOCIAL_AUTH_OKTA_OAUTH2_SECRET = ''
SOCIAL_AUTH_OKTA_OAUTH2_API_URL = ''
```

<a id="okta-openid-connect"></a>

## Okta OpenID Connect

<a id="id1"></a>

### IdP Setup

Follow the same steps as OAuth2 above, but use the redirect URI:

```default
https://your-domain.com/complete/okta-openidconnect/
```

<a id="id2"></a>

### Application Configuration

Fill `Client ID`, `Client Secret` and `API URL (e.g.
https://dev-123456.okta.com/oauth2)` settings with the values from the IdP setup:

```default
SOCIAL_AUTH_OKTA_OPENIDCONNECT_KEY = ''
SOCIAL_AUTH_OKTA_OPENIDCONNECT_SECRET = ''
SOCIAL_AUTH_OKTA_OPENIDCONNECT_API_URL = ''
```

<a id="scopes-and-external-groups"></a>

## Scopes and external groups

Both backends request `openid`, `profile`, and `email` by default.
For the org authorization server (`/oauth2/v1/authorize`), request the
`groups` scope with the setting matching your backend:

```default
# social_core.backends.okta.OktaOAuth2
SOCIAL_AUTH_OKTA_OAUTH2_SCOPE = ['groups']

# social_core.backends.okta_openidconnect.OktaOpenIdConnect
SOCIAL_AUTH_OKTA_OPENIDCONNECT_SCOPE = ['groups']
```

These settings add to the default scopes. `SOCIAL_AUTH_OIDC_SCOPE` applies
only to the generic OpenID Connect backend.

For a custom authorization server (`/oauth2/{authorizationServerId}/v1/authorize`,
including `default`), `groups` is not an automatically defined scope.
Configure the groups claim for any scope or for specific scopes, then request
any scope associated with that claim using the matching `SCOPE` setting.
If the claim is available with the default scopes, no additional scope is
needed; Okta’s custom-server example requests only `openid`. Request
`groups` only if you have defined that scope on the custom server and
associated it with the claim; requesting an undefined scope causes
`invalid_scope`.

Configure Okta to issue a groups claim with an appropriate group filter;
requesting a scope alone does not configure the claim. See
[Okta’s groups claim guide](https://developer.okta.com/docs/guides/customize-tokens-groups-claim/main/)
for org and custom authorization server configuration.

Group extraction and local synchronization are opt-in. For `OktaOAuth2`,
configure the literal claim name and map external groups to existing Django
group names:

```default
SOCIAL_AUTH_OKTA_OAUTH2_GROUPS_KEY = 'groups'
SOCIAL_AUTH_OKTA_OAUTH2_GROUPS_MAP = {
    'engineering': ['Engineering'],
}

from social_core.pipeline import DEFAULT_AUTH_PIPELINE

SOCIAL_AUTH_PIPELINE = (
    *DEFAULT_AUTH_PIPELINE,
    'social_core.pipeline.user.sync_groups',
)
```

For `OktaOpenIdConnect`, use the corresponding settings with the same
pipeline:

```default
SOCIAL_AUTH_OKTA_OPENIDCONNECT_GROUPS_KEY = 'groups'
SOCIAL_AUTH_OKTA_OPENIDCONNECT_GROUPS_MAP = {
    'engineering': ['Engineering'],
}
```

`OktaOAuth2` reads the claim from UserInfo. `OktaOpenIdConnect` prefers the
validated ID token and falls back to UserInfo only when its subject matches
the ID token. Enabling extraction does not automatically request additional
scopes.

Synchronization adds desired mapped memberships and removes obsolete mapped
memberships, preserving unrelated Django groups. It does not create groups.
An empty claim clears managed memberships; a missing configured claim fails
authentication by default. If Okta omits the claim for users with no groups,
explicitly set `SOCIAL_AUTH_OKTA_OAUTH2_GROUPS_MISSING_AS_EMPTY = True` or
`SOCIAL_AUTH_OKTA_OPENIDCONNECT_GROUPS_MISSING_AS_EMPTY = True` for your
backend. Malformed claims still fail authentication.

See [External groups](../groups.html.md) for validation, authentication restrictions, and
synchronization behavior.

<a id="user-identification"></a>

## User identification

Both Okta backends identify users by the stable `sub` claim. Associations
created by older social-core releases used `preferred_username` and migrate
to `sub` on the next successful authentication. See [Configurable User ID
Key](../configuration/settings.html#configurable-user-id-key) for migration controls and custom identifier settings.
