diff --git a/authentik/sources/oauth/apps.py b/authentik/sources/oauth/apps.py index d89838476..1dbeb54e1 100644 --- a/authentik/sources/oauth/apps.py +++ b/authentik/sources/oauth/apps.py @@ -14,6 +14,7 @@ AUTHENTIK_SOURCES_OAUTH_TYPES = [ "authentik.sources.oauth.types.github", "authentik.sources.oauth.types.google", "authentik.sources.oauth.types.oidc", + "authentik.sources.oauth.types.okta", "authentik.sources.oauth.types.reddit", "authentik.sources.oauth.types.twitter", ] diff --git a/authentik/sources/oauth/models.py b/authentik/sources/oauth/models.py index 7276d7575..f48e2a9c7 100644 --- a/authentik/sources/oauth/models.py +++ b/authentik/sources/oauth/models.py @@ -183,6 +183,16 @@ class AppleOAuthSource(OAuthSource): verbose_name_plural = _("Apple OAuth Sources") +class OktaOAuthSource(OAuthSource): + """Login using a okta.com.""" + + class Meta: + + abstract = True + verbose_name = _("Okta OAuth Source") + verbose_name_plural = _("Okta OAuth Sources") + + class UserOAuthSourceConnection(UserSourceConnection): """Authorized remote OAuth provider.""" diff --git a/authentik/sources/oauth/types/okta.py b/authentik/sources/oauth/types/okta.py new file mode 100644 index 000000000..5f03bda53 --- /dev/null +++ b/authentik/sources/oauth/types/okta.py @@ -0,0 +1,51 @@ +"""Okta OAuth Views""" +from typing import Any + +from authentik.sources.oauth.models import OAuthSource +from authentik.sources.oauth.types.azure_ad import AzureADClient +from authentik.sources.oauth.types.manager import MANAGER, SourceType +from authentik.sources.oauth.views.callback import OAuthCallback +from authentik.sources.oauth.views.redirect import OAuthRedirect + + +class OktaOAuthRedirect(OAuthRedirect): + """Okta OAuth2 Redirect""" + + def get_additional_parameters(self, source: OAuthSource): # pragma: no cover + return { + "scope": "openid email profile", + } + + +class OktaOAuth2Callback(OAuthCallback): + """Okta OAuth2 Callback""" + + # Okta has the same quirk as azure and throws an error if the access token + # is set via query parameter, so we re-use the azure client + # see https://github.com/goauthentik/authentik/issues/1910 + client_class = AzureADClient + + def get_user_id(self, info: dict[str, str]) -> str: + return info.get("sub", "") + + def get_user_enroll_context( + self, + info: dict[str, Any], + ) -> dict[str, Any]: + return { + "username": info.get("nickname"), + "email": info.get("email"), + "name": info.get("name"), + } + + +@MANAGER.type() +class OktaType(SourceType): + """Okta Type definition""" + + callback_view = OktaOAuth2Callback + redirect_view = OktaOAuthRedirect + name = "Okta" + slug = "okta" + + urls_customizable = True diff --git a/schema.yml b/schema.yml index 7247a8723..29522b730 100644 --- a/schema.yml +++ b/schema.yml @@ -28992,6 +28992,7 @@ components: - github - google - openidconnect + - okta - reddit - twitter type: string diff --git a/web/authentik/sources/okta.svg b/web/authentik/sources/okta.svg new file mode 100644 index 000000000..5595186b2 --- /dev/null +++ b/web/authentik/sources/okta.svg @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + + diff --git a/web/src/api/Sentry.ts b/web/src/api/Sentry.ts index 11990cf00..8014b2e70 100644 --- a/web/src/api/Sentry.ts +++ b/web/src/api/Sentry.ts @@ -44,7 +44,7 @@ export function configureSentry(canDoPpi: boolean = false): Promise { if (window.location.pathname.includes("if/")) { // Get the interface name from URL const pathMatches = window.location.pathname.match(/.+if\/(\w+)\//); - let currentInterface = "unkown"; + let currentInterface = "unknown"; if (pathMatches && pathMatches.length >= 2) { currentInterface = pathMatches[1]; }