diff --git a/authentik/sources/oauth/apps.py b/authentik/sources/oauth/apps.py index 657a5d942..d89838476 100644 --- a/authentik/sources/oauth/apps.py +++ b/authentik/sources/oauth/apps.py @@ -7,14 +7,15 @@ from structlog.stdlib import get_logger LOGGER = get_logger() AUTHENTIK_SOURCES_OAUTH_TYPES = [ + "authentik.sources.oauth.types.apple", + "authentik.sources.oauth.types.azure_ad", "authentik.sources.oauth.types.discord", "authentik.sources.oauth.types.facebook", "authentik.sources.oauth.types.github", "authentik.sources.oauth.types.google", + "authentik.sources.oauth.types.oidc", "authentik.sources.oauth.types.reddit", "authentik.sources.oauth.types.twitter", - "authentik.sources.oauth.types.azure_ad", - "authentik.sources.oauth.types.oidc", ] diff --git a/authentik/sources/oauth/clients/base.py b/authentik/sources/oauth/clients/base.py index df1e07054..401f39656 100644 --- a/authentik/sources/oauth/clients/base.py +++ b/authentik/sources/oauth/clients/base.py @@ -1,6 +1,6 @@ """OAuth Clients""" from typing import Any, Optional -from urllib.parse import urlencode +from urllib.parse import quote, urlencode from django.http import HttpRequest from requests import Session @@ -58,7 +58,7 @@ class BaseOAuthClient: args = self.get_redirect_args() additional = parameters or {} args.update(additional) - params = urlencode(args) + params = urlencode(args, quote_via=quote) LOGGER.info("redirect args", **args) authorization_url = self.source.type.authorization_url or "" if self.source.type.urls_customizable and self.source.authorization_url: diff --git a/authentik/sources/oauth/clients/oauth2.py b/authentik/sources/oauth/clients/oauth2.py index b3c822812..cd91acb16 100644 --- a/authentik/sources/oauth/clients/oauth2.py +++ b/authentik/sources/oauth/clients/oauth2.py @@ -20,10 +20,16 @@ class OAuth2Client(BaseOAuthClient): "Accept": "application/json", } + def get_request_arg(self, key: str, default: Optional[Any] = None) -> Any: + """Depending on request type, get data from post or get""" + if self.request.method == "POST": + return self.request.POST.get(key, default) + return self.request.GET.get(key, default) + def check_application_state(self) -> bool: "Check optional state parameter." stored = self.request.session.get(self.session_key, None) - returned = self.request.GET.get("state", None) + returned = self.get_request_arg("state", None) check = False if stored is not None: if returned is not None: @@ -38,23 +44,31 @@ class OAuth2Client(BaseOAuthClient): "Generate state optional parameter." return get_random_string(32) + def get_client_id(self) -> str: + """Get client id""" + return self.source.consumer_key + + def get_client_secret(self) -> str: + """Get client secret""" + return self.source.consumer_secret + def get_access_token(self, **request_kwargs) -> Optional[dict[str, Any]]: "Fetch access token from callback request." callback = self.request.build_absolute_uri(self.callback or self.request.path) if not self.check_application_state(): LOGGER.warning("Application state check failed.") return None - if "code" in self.request.GET: - args = { - "client_id": self.source.consumer_key, - "redirect_uri": callback, - "client_secret": self.source.consumer_secret, - "code": self.request.GET["code"], - "grant_type": "authorization_code", - } - else: + code = self.get_request_arg("code", None) + if not code: LOGGER.warning("No code returned by the source") return None + args = { + "client_id": self.get_client_id(), + "client_secret": self.get_client_secret(), + "redirect_uri": callback, + "code": code, + "grant_type": "authorization_code", + } try: access_token_url = self.source.type.access_token_url or "" if self.source.type.urls_customizable and self.source.access_token_url: @@ -75,7 +89,7 @@ class OAuth2Client(BaseOAuthClient): def get_redirect_args(self) -> dict[str, str]: "Get request parameters for redirect url." callback = self.request.build_absolute_uri(self.callback) - client_id: str = self.source.consumer_key + client_id: str = self.get_client_id() args: dict[str, str] = { "client_id": client_id, "redirect_uri": callback, diff --git a/authentik/sources/oauth/models.py b/authentik/sources/oauth/models.py index 5c16178eb..7276d7575 100644 --- a/authentik/sources/oauth/models.py +++ b/authentik/sources/oauth/models.py @@ -2,7 +2,6 @@ from typing import TYPE_CHECKING, Optional, Type from django.db import models -from django.templatetags.static import static from django.urls import reverse from django.utils.translation import gettext_lazy as _ from rest_framework.serializers import Serializer @@ -49,7 +48,7 @@ class OAuthSource(Source): consumer_secret = models.TextField() @property - def type(self) -> "SourceType": + def type(self) -> Type["SourceType"]: """Return the provider instance for this source""" from authentik.sources.oauth.types.manager import MANAGER @@ -67,6 +66,7 @@ class OAuthSource(Source): @property def ui_login_button(self) -> UILoginButton: + provider_type = self.type return UILoginButton( challenge=RedirectChallenge( instance={ @@ -77,7 +77,7 @@ class OAuthSource(Source): ), } ), - icon_url=static(f"authentik/sources/{self.provider_type}.svg"), + icon_url=provider_type().icon_url(), name=self.name, ) @@ -173,6 +173,16 @@ class OpenIDConnectOAuthSource(OAuthSource): verbose_name_plural = _("OpenID OAuth Sources") +class AppleOAuthSource(OAuthSource): + """Login using a apple.com.""" + + class Meta: + + abstract = True + verbose_name = _("Apple OAuth Source") + verbose_name_plural = _("Apple OAuth Sources") + + class UserOAuthSourceConnection(UserSourceConnection): """Authorized remote OAuth provider.""" diff --git a/authentik/sources/oauth/types/apple.py b/authentik/sources/oauth/types/apple.py new file mode 100644 index 000000000..d829f62f9 --- /dev/null +++ b/authentik/sources/oauth/types/apple.py @@ -0,0 +1,102 @@ +"""Apple OAuth Views""" +from base64 import b64decode +from json import loads +from time import time +from typing import Any, Optional + +from jwt import encode +from structlog.stdlib import get_logger + +from authentik.sources.oauth.clients.oauth2 import OAuth2Client +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 + +LOGGER = get_logger() + + +class AppleOAuthClient(OAuth2Client): + """Apple OAuth2 client""" + + def get_client_id(self) -> str: + parts = self.source.consumer_key.split(";") + if len(parts) < 3: + return self.source.consumer_key + return parts[0] + + def get_client_secret(self) -> str: + now = time() + parts = self.source.consumer_key.split(";") + if len(parts) < 3: + raise ValueError( + ( + "Apple Source client_id should be formatted like " + "services_id_identifier;apple_team_id;key_id" + ) + ) + LOGGER.debug("got values from client_id", team=parts[1], kid=parts[2]) + payload = { + "iss": parts[1], + "iat": now, + "exp": now + 86400 * 180, + "aud": "https://appleid.apple.com", + "sub": self.source.consumer_key, + } + # pyright: reportGeneralTypeIssues=false + jwt = encode(payload, self.source.consumer_secret, "ES256", {"kid": parts[2]}) + LOGGER.debug("signing payload as secret key", payload=payload, jwt=jwt) + return jwt + + def get_profile_info(self, token: dict[str, str]) -> Optional[dict[str, Any]]: + id_token = token.get("id_token") + _, raw_payload, _ = id_token.split(".") + payload = loads(b64decode(raw_payload.encode().decode())) + return payload + + +class AppleOAuthRedirect(OAuthRedirect): + """Apple OAuth2 Redirect""" + + client_class = AppleOAuthClient + + def get_additional_parameters(self, source): # pragma: no cover + return { + "scope": "name email", + "response_mode": "form_post", + } + + +class AppleOAuth2Callback(OAuthCallback): + """Apple OAuth2 Callback""" + + client_class = AppleOAuthClient + + def get_user_id(self, info: dict[str, Any]) -> Optional[str]: + return info["sub"] + + def get_user_enroll_context( + self, + info: dict[str, Any], + ) -> dict[str, Any]: + print(info) + return { + "email": info.get("email"), + "name": info.get("name"), + } + + +@MANAGER.type() +class AppleType(SourceType): + """Apple Type definition""" + + callback_view = AppleOAuth2Callback + redirect_view = AppleOAuthRedirect + name = "Apple" + slug = "apple" + + authorization_url = "https://appleid.apple.com/auth/authorize" + access_token_url = "https://appleid.apple.com/auth/token" # nosec + profile_url = "" + + def icon_url(self) -> str: + return "https://appleid.cdn-apple.com/appleid/button/logo" diff --git a/authentik/sources/oauth/types/manager.py b/authentik/sources/oauth/types/manager.py index 268b42b81..f619148d8 100644 --- a/authentik/sources/oauth/types/manager.py +++ b/authentik/sources/oauth/types/manager.py @@ -1,7 +1,8 @@ """Source type manager""" from enum import Enum -from typing import Callable, Optional +from typing import Callable, Optional, Type +from django.templatetags.static import static from structlog.stdlib import get_logger from authentik.sources.oauth.views.callback import OAuthCallback @@ -22,8 +23,8 @@ class SourceType: callback_view = OAuthCallback redirect_view = OAuthRedirect - name: str - slug: str + name: str = "default" + slug: str = "default" urls_customizable = False @@ -32,12 +33,16 @@ class SourceType: access_token_url: Optional[str] = None profile_url: Optional[str] = None + def icon_url(self) -> str: + """Get Icon URL for login""" + return static(f"authentik/sources/{self.slug}.svg") + class SourceTypeManager: """Manager to hold all Source types.""" def __init__(self) -> None: - self.__sources: list[SourceType] = [] + self.__sources: list[Type[SourceType]] = [] def type(self): """Class decorator to register classes inline.""" @@ -56,14 +61,14 @@ class SourceTypeManager: """Get list of tuples of all registered names""" return [(x.slug, x.name) for x in self.__sources] - def find_type(self, type_name: str) -> SourceType: + def find_type(self, type_name: str) -> Type[SourceType]: """Find type based on source""" found_type = None for src_type in self.__sources: if src_type.slug == type_name: return src_type if not found_type: - found_type = SourceType() + found_type = SourceType LOGGER.warning( "no matching type found, using default", wanted=type_name, diff --git a/authentik/sources/oauth/views/callback.py b/authentik/sources/oauth/views/callback.py index a192382dd..b745ac25f 100644 --- a/authentik/sources/oauth/views/callback.py +++ b/authentik/sources/oauth/views/callback.py @@ -24,7 +24,7 @@ class OAuthCallback(OAuthClientMixin, View): source: OAuthSource # pylint: disable=too-many-return-statements - def get(self, request: HttpRequest, *_, **kwargs) -> HttpResponse: + def dispatch(self, request: HttpRequest, *_, **kwargs) -> HttpResponse: """View Get handler""" slug = kwargs.get("source_slug", "") try: diff --git a/authentik/sources/oauth/views/dispatcher.py b/authentik/sources/oauth/views/dispatcher.py index 4ee0cf3b2..557153fe7 100644 --- a/authentik/sources/oauth/views/dispatcher.py +++ b/authentik/sources/oauth/views/dispatcher.py @@ -1,6 +1,8 @@ """Dispatch OAuth views to respective views""" from django.shortcuts import get_object_or_404 +from django.utils.decorators import method_decorator from django.views import View +from django.views.decorators.csrf import csrf_exempt from structlog.stdlib import get_logger from authentik.sources.oauth.models import OAuthSource @@ -9,6 +11,7 @@ from authentik.sources.oauth.types.manager import MANAGER, RequestKind LOGGER = get_logger() +@method_decorator(csrf_exempt, name="dispatch") class DispatcherView(View): """Dispatch OAuth Redirect/Callback views to their proper class based on URL parameters""" diff --git a/authentik/stages/identification/tests.py b/authentik/stages/identification/tests.py index 54e81c6dd..085fb81c9 100644 --- a/authentik/stages/identification/tests.py +++ b/authentik/stages/identification/tests.py @@ -119,7 +119,7 @@ class TestIdentificationStage(APITestCase): "to": "/source/oauth/login/test/", "type": ChallengeTypes.REDIRECT.value, }, - "icon_url": "/static/authentik/sources/.svg", + "icon_url": "/static/authentik/sources/default.svg", "name": "test", } ], @@ -170,7 +170,7 @@ class TestIdentificationStage(APITestCase): "to": "/source/oauth/login/test/", "type": ChallengeTypes.REDIRECT.value, }, - "icon_url": "/static/authentik/sources/.svg", + "icon_url": "/static/authentik/sources/default.svg", "name": "test", } ], @@ -226,7 +226,7 @@ class TestIdentificationStage(APITestCase): }, "sources": [ { - "icon_url": "/static/authentik/sources/.svg", + "icon_url": "/static/authentik/sources/default.svg", "name": "test", "challenge": { "component": "xak-flow-redirect", @@ -280,7 +280,7 @@ class TestIdentificationStage(APITestCase): "to": "/source/oauth/login/test/", "type": ChallengeTypes.REDIRECT.value, }, - "icon_url": "/static/authentik/sources/.svg", + "icon_url": "/static/authentik/sources/default.svg", "name": "test", } ], diff --git a/locale/en/LC_MESSAGES/django.po b/locale/en/LC_MESSAGES/django.po index 51efe20d4..05330a249 100644 --- a/locale/en/LC_MESSAGES/django.po +++ b/locale/en/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2021-10-11 14:12+0000\n" +"POT-Creation-Date: 2021-10-18 10:40+0000\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -308,6 +308,10 @@ msgstr "" msgid "Notification Webhook Mappings" msgstr "" +#: authentik/events/monitored_tasks.py:122 +msgid "Task has not been run yet." +msgstr "" + #: authentik/flows/api/flows.py:350 #, python-format msgid "Flow not applicable to current user/request: %(messages)s" @@ -385,33 +389,33 @@ msgstr "" msgid "Invalid kubeconfig" msgstr "" -#: authentik/outposts/models.py:164 +#: authentik/outposts/models.py:167 msgid "Outpost Service-Connection" msgstr "" -#: authentik/outposts/models.py:165 +#: authentik/outposts/models.py:168 msgid "Outpost Service-Connections" msgstr "" -#: authentik/outposts/models.py:201 +#: authentik/outposts/models.py:204 msgid "" "Certificate/Key used for authentication. Can be left empty for no " "authentication." msgstr "" -#: authentik/outposts/models.py:243 +#: authentik/outposts/models.py:246 msgid "Docker Service-Connection" msgstr "" -#: authentik/outposts/models.py:244 +#: authentik/outposts/models.py:247 msgid "Docker Service-Connections" msgstr "" -#: authentik/outposts/models.py:290 +#: authentik/outposts/models.py:293 msgid "Kubernetes Service-Connection" msgstr "" -#: authentik/outposts/models.py:291 +#: authentik/outposts/models.py:294 msgid "Kubernetes Service-Connections" msgstr "" @@ -988,108 +992,116 @@ msgstr "" msgid "Password does not match Active Directory Complexity." msgstr "" -#: authentik/sources/oauth/models.py:25 +#: authentik/sources/oauth/models.py:24 msgid "Request Token URL" msgstr "" -#: authentik/sources/oauth/models.py:27 +#: authentik/sources/oauth/models.py:26 msgid "" "URL used to request the initial token. This URL is only required for OAuth 1." msgstr "" -#: authentik/sources/oauth/models.py:33 +#: authentik/sources/oauth/models.py:32 msgid "Authorization URL" msgstr "" -#: authentik/sources/oauth/models.py:34 +#: authentik/sources/oauth/models.py:33 msgid "URL the user is redirect to to conest the flow." msgstr "" -#: authentik/sources/oauth/models.py:39 +#: authentik/sources/oauth/models.py:38 msgid "Access Token URL" msgstr "" -#: authentik/sources/oauth/models.py:40 +#: authentik/sources/oauth/models.py:39 msgid "URL used by authentik to retrieve tokens." msgstr "" -#: authentik/sources/oauth/models.py:45 +#: authentik/sources/oauth/models.py:44 msgid "Profile URL" msgstr "" -#: authentik/sources/oauth/models.py:46 +#: authentik/sources/oauth/models.py:45 msgid "URL used by authentik to get user information." msgstr "" -#: authentik/sources/oauth/models.py:102 +#: authentik/sources/oauth/models.py:101 msgid "OAuth Source" msgstr "" -#: authentik/sources/oauth/models.py:103 +#: authentik/sources/oauth/models.py:102 msgid "OAuth Sources" msgstr "" -#: authentik/sources/oauth/models.py:112 +#: authentik/sources/oauth/models.py:111 msgid "GitHub OAuth Source" msgstr "" -#: authentik/sources/oauth/models.py:113 +#: authentik/sources/oauth/models.py:112 msgid "GitHub OAuth Sources" msgstr "" -#: authentik/sources/oauth/models.py:122 +#: authentik/sources/oauth/models.py:121 msgid "Twitter OAuth Source" msgstr "" -#: authentik/sources/oauth/models.py:123 +#: authentik/sources/oauth/models.py:122 msgid "Twitter OAuth Sources" msgstr "" -#: authentik/sources/oauth/models.py:132 +#: authentik/sources/oauth/models.py:131 msgid "Facebook OAuth Source" msgstr "" -#: authentik/sources/oauth/models.py:133 +#: authentik/sources/oauth/models.py:132 msgid "Facebook OAuth Sources" msgstr "" -#: authentik/sources/oauth/models.py:142 +#: authentik/sources/oauth/models.py:141 msgid "Discord OAuth Source" msgstr "" -#: authentik/sources/oauth/models.py:143 +#: authentik/sources/oauth/models.py:142 msgid "Discord OAuth Sources" msgstr "" -#: authentik/sources/oauth/models.py:152 +#: authentik/sources/oauth/models.py:151 msgid "Google OAuth Source" msgstr "" -#: authentik/sources/oauth/models.py:153 +#: authentik/sources/oauth/models.py:152 msgid "Google OAuth Sources" msgstr "" -#: authentik/sources/oauth/models.py:162 +#: authentik/sources/oauth/models.py:161 msgid "Azure AD OAuth Source" msgstr "" -#: authentik/sources/oauth/models.py:163 +#: authentik/sources/oauth/models.py:162 msgid "Azure AD OAuth Sources" msgstr "" -#: authentik/sources/oauth/models.py:172 +#: authentik/sources/oauth/models.py:171 msgid "OpenID OAuth Source" msgstr "" -#: authentik/sources/oauth/models.py:173 +#: authentik/sources/oauth/models.py:172 msgid "OpenID OAuth Sources" msgstr "" -#: authentik/sources/oauth/models.py:188 +#: authentik/sources/oauth/models.py:181 +msgid "Apple OAuth Source" +msgstr "" + +#: authentik/sources/oauth/models.py:182 +msgid "Apple OAuth Sources" +msgstr "" + +#: authentik/sources/oauth/models.py:197 msgid "User OAuth Source Connection" msgstr "" -#: authentik/sources/oauth/models.py:189 +#: authentik/sources/oauth/models.py:198 msgid "User OAuth Source Connections" msgstr "" @@ -1214,19 +1226,19 @@ msgstr "" msgid "Duo Devices" msgstr "" -#: authentik/stages/authenticator_sms/models.py:97 +#: authentik/stages/authenticator_sms/models.py:158 msgid "SMS Authenticator Setup Stage" msgstr "" -#: authentik/stages/authenticator_sms/models.py:98 +#: authentik/stages/authenticator_sms/models.py:159 msgid "SMS Authenticator Setup Stages" msgstr "" -#: authentik/stages/authenticator_sms/models.py:116 +#: authentik/stages/authenticator_sms/models.py:176 msgid "SMS Device" msgstr "" -#: authentik/stages/authenticator_sms/models.py:117 +#: authentik/stages/authenticator_sms/models.py:177 msgid "SMS Devices" msgstr "" @@ -1291,19 +1303,19 @@ msgstr "" msgid "Authenticator Validation Stages" msgstr "" -#: authentik/stages/authenticator_webauthn/models.py:49 +#: authentik/stages/authenticator_webauthn/models.py:51 msgid "WebAuthn Authenticator Setup Stage" msgstr "" -#: authentik/stages/authenticator_webauthn/models.py:50 +#: authentik/stages/authenticator_webauthn/models.py:52 msgid "WebAuthn Authenticator Setup Stages" msgstr "" -#: authentik/stages/authenticator_webauthn/models.py:78 +#: authentik/stages/authenticator_webauthn/models.py:85 msgid "WebAuthn Device" msgstr "" -#: authentik/stages/authenticator_webauthn/models.py:79 +#: authentik/stages/authenticator_webauthn/models.py:86 msgid "WebAuthn Devices" msgstr "" diff --git a/tests/e2e/test_source_oauth.py b/tests/e2e/test_source_oauth.py index 070487a1f..8a847e3fb 100644 --- a/tests/e2e/test_source_oauth.py +++ b/tests/e2e/test_source_oauth.py @@ -43,7 +43,7 @@ class OAUth1Type(SourceType): urls_customizable = False -SOURCE_TYPE_MOCK = Mock(return_value=OAUth1Type()) +SOURCE_TYPE_MOCK = Mock(return_value=OAUth1Type) @skipUnless(platform.startswith("linux"), "requires local docker") diff --git a/web/src/pages/sources/oauth/OAuthSourceForm.ts b/web/src/pages/sources/oauth/OAuthSourceForm.ts index c5e46280f..bc3a12842 100644 --- a/web/src/pages/sources/oauth/OAuthSourceForm.ts +++ b/web/src/pages/sources/oauth/OAuthSourceForm.ts @@ -252,7 +252,7 @@ export class OAuthSourceForm extends ModelForm { ?writeOnly=${this.instance !== undefined} name="consumerSecret" > - + diff --git a/website/docs/integrations/services/bookstack/index.md b/website/docs/integrations/services/bookstack/index.md index 1c2c60a0b..7fb4d4942 100644 --- a/website/docs/integrations/services/bookstack/index.md +++ b/website/docs/integrations/services/bookstack/index.md @@ -50,7 +50,7 @@ In authentik, create an application which uses this provider. Optionally apply a ### Step 3 -Obtain your Metadata URL from Authentik. +Obtain your Metadata URL from authentik. 1. Click on the BookStack Provider 2. Click the Metadata Tab @@ -69,7 +69,7 @@ Modify the following Example SAML config and paste incorporate into your `.env` AUTH_METHOD=saml2 # Set the display name to be shown on the login button. # (Login with ) -SAML2_NAME=Authentik +SAML2_NAME=authentik # Name of the attribute which provides the user's email address SAML2_EMAIL_ATTRIBUTE=email # Name of the attribute to use as an ID for the SAML user. diff --git a/website/docs/integrations/services/portainer/index.md b/website/docs/integrations/services/portainer/index.md index f388a9ada..b26713195 100644 --- a/website/docs/integrations/services/portainer/index.md +++ b/website/docs/integrations/services/portainer/index.md @@ -21,7 +21,7 @@ The following placeholders will be used: - `port.company` is the FQDN of Portainer. - `authentik.company` is the FQDN of authentik. -### Step 1 - Authentik +### Step 1 - authentik In authentik, under _Providers_, create an _OAuth2/OpenID Provider_ with these settings: @@ -57,7 +57,7 @@ Portainer by default shows commas between each item in the Scopes field. Do **N ![](./port1.png) -### Step 3 - Authentik +### Step 3 - authentik In authentik, create an application which uses this provider. Optionally apply access restrictions to the application using policy bindings. diff --git a/website/docs/integrations/services/vikunja/index.md b/website/docs/integrations/services/vikunja/index.md index 3485c128e..8cea6cdb5 100644 --- a/website/docs/integrations/services/vikunja/index.md +++ b/website/docs/integrations/services/vikunja/index.md @@ -76,9 +76,9 @@ auth: # The auth url to send users to if they want to authenticate using OpenID Connect. authurl: https://authentik.company/application/o/vikunja/ # The client ID used to authenticate Vikunja at the OpenID Connect provider. - clientid: THIS IS THE CLIENT ID YOU COPIED FROM STEP 1 in Authentik + clientid: THIS IS THE CLIENT ID YOU COPIED FROM STEP 1 in authentik # The client secret used to authenticate Vikunja at the OpenID Connect provider. - clientsecret: THIS IS THE CLIENT SECRET YOU COPIED FROM STEP 1 in Authentik + clientsecret: THIS IS THE CLIENT SECRET YOU COPIED FROM STEP 1 in authentik ``` :::note diff --git a/website/docs/integrations/services/wekan/index.mdx b/website/docs/integrations/services/wekan/index.mdx index 714e2d4b5..73fbd75a0 100644 --- a/website/docs/integrations/services/wekan/index.mdx +++ b/website/docs/integrations/services/wekan/index.mdx @@ -39,7 +39,7 @@ import TabItem from '@theme/TabItem'; {label: 'Standalone', value: 'standalone'}, ]}> -If your Wekan is running in docker, add the following environment variables for Authentik +If your Wekan is running in docker, add the following environment variables for authentik ```yaml environment: @@ -58,11 +58,11 @@ environment: ``` - + edit `.env` and add the following: ```ini - # Authentik OAUTH Config + # authentik OAUTH Config OAUTH2_ENABLED='true' OAUTH2_LOGIN_STYLE='redirect' OAUTH2_CLIENT_ID='' diff --git a/website/docs/integrations/services/wordpress/index.md b/website/docs/integrations/services/wordpress/index.md index fb1580f9e..b1a7bee70 100644 --- a/website/docs/integrations/services/wordpress/index.md +++ b/website/docs/integrations/services/wordpress/index.md @@ -21,7 +21,7 @@ The following placeholders will be used: - `wp.company` is the FQDN of Wordpress. - `authentik.company` is the FQDN of authentik. -### Step 1 - Authentik +### Step 1 - authentik In authentik, under _Providers_, create an _OAuth2/OpenID Provider_ with these settings: @@ -63,7 +63,7 @@ Only settings that have been modified from default have been listed. Review each setting and choose the ones that you require for your installation. Examples of popular settings are _Link Existing Users_, _Create user if does not exist_, and _Enforce Privacy_ ::: -### Step 3 - Authentik +### Step 3 - authentik In authentik, create an application which uses this provider. Optionally apply access restrictions to the application using policy bindings. diff --git a/website/docs/integrations/sources/apple/app_id.png b/website/docs/integrations/sources/apple/app_id.png new file mode 100644 index 000000000..a90925dd2 Binary files /dev/null and b/website/docs/integrations/sources/apple/app_id.png differ diff --git a/website/docs/integrations/sources/apple/app_service_config.png b/website/docs/integrations/sources/apple/app_service_config.png new file mode 100644 index 000000000..3b57e2be8 Binary files /dev/null and b/website/docs/integrations/sources/apple/app_service_config.png differ diff --git a/website/docs/integrations/sources/apple/index.md b/website/docs/integrations/sources/apple/index.md new file mode 100644 index 000000000..8c6ecb44d --- /dev/null +++ b/website/docs/integrations/sources/apple/index.md @@ -0,0 +1,67 @@ +--- +title: Apple +--- + +Allows users to authenticate using their Apple ID. + +## Preparation + +:::warning +An Apple developer account is required for this. +::: + +The following placeholders will be used: + +- `authentik.company` is the FQDN of the authentik install. + +## Apple + +1. Log into your Apple developer account, and navigate to **Certificates, IDs & Profiles**, then click **Identifiers** in the sidebar. +2. Register a new Identifier with the type of **App IDs**, and the subtype **App**. +3. Choose a name that users will recognise for the **Description** field. +4. For your bundle ID, use the reverse domain of authentik, in this case `company.authentik`. +5. Scroll down the list of capabilities, and check the box next to **Sign In with Apple**. +6. At the top, click **Continue** and **Register**. + +![](app_id.png) + +7. Register another new Identifier with the type of **Services IDs**. +8. Again, choose the same name as above for your **Description** field. +9. Use the same identifier as above, but add a suffix like `signin` or `oauth`, as identifiers are unique. +10. At the top, click **Continue** and **Register**. + +![](service_id.png) + +11. Once back at the overview list, click on the just-created Identifier. +12. Enable the checkbox next to **Sign In with Apple**, and click **Configure** +13. Under domains, enter `authentik.company`. +14. Under **Return URLs**, enter `https://authentik.company/source/oauth/callback/apple/`. + +![](app_service_config.png) + +15. Click on **Keys** in the sidebar. Register a new Key with any name, and select **Sign in with Apple**. +16. Click on **Configure**, and select the App ID you've created above. +17. At the top, click **Save**, **Continue** and **Register**. +18. Download the Key file and note the **Key ID**. + +![](key.png) + +19. Note the Team ID, visible at the top of the page. + +## authentik + +20. Under _Resources -> Sources_ Click **Create Apple OAuth Source** + +21. **Name**: `Apple` +22. **Slug**: `apple` +23. **Consumer Key:** The identifier from step 9, then `;`, then your Team ID from step 19, then `;`, then the Key ID from step 18. + + Example: `io.goauthentik.dev-local;JQNH45HN7V;XFBNJ82BV6` + +24. **Consumer Secret:** Paste the contents of the keyfile you've downloaded + +Save, and you now have Apple as a source. + +:::note +For more details on how-to have the new source display on the Login Page see the Sources page. +::: diff --git a/website/docs/integrations/sources/apple/key.png b/website/docs/integrations/sources/apple/key.png new file mode 100644 index 000000000..0c585e432 Binary files /dev/null and b/website/docs/integrations/sources/apple/key.png differ diff --git a/website/docs/integrations/sources/apple/service_id.png b/website/docs/integrations/sources/apple/service_id.png new file mode 100644 index 000000000..b62e2afb7 Binary files /dev/null and b/website/docs/integrations/sources/apple/service_id.png differ diff --git a/website/docs/integrations/sources/discord/index.md b/website/docs/integrations/sources/discord/index.md index 341e42244..c119cc511 100644 --- a/website/docs/integrations/sources/discord/index.md +++ b/website/docs/integrations/sources/discord/index.md @@ -33,7 +33,7 @@ Here is an example of a completed OAuth2 screen for Discord. ![Example Screen](discord4.png) -## Authentik +## authentik 8. Under _Resources -> Sources_ Click **Create Discord OAuth Source** @@ -43,7 +43,7 @@ Here is an example of a completed OAuth2 screen for Discord. 12. **Consumer Secret:** Client Secret from step 5 13. **Provider type:** Discord -Here is an exmple of a complete Authentik Discord OAuth Source +Here is an example of a complete authentik Discord OAuth Source ![Example Screen](discord5.png) @@ -51,4 +51,4 @@ Save, and you now have Discord as a source. :::note For more details on how-to have the new source display on the Login Page see the Sources page -::: \ No newline at end of file +::: diff --git a/website/docs/integrations/sources/github/index.md b/website/docs/integrations/sources/github/index.md index c8949e45c..6e9d9d541 100644 --- a/website/docs/integrations/sources/github/index.md +++ b/website/docs/integrations/sources/github/index.md @@ -17,7 +17,7 @@ The following placeholders will be used: ![Register OAuth App](githubdeveloper1.png) -2. **Application Name:** Choose a name users will recognize ie: Authentik +2. **Application Name:** Choose a name users will recognize ie: authentik 3. **Homepage URL**:: www.my.company 4. **Authorization callback URL**: https://authentik.company/source/oauth/callback/github 5. Click **Register Application** @@ -27,9 +27,9 @@ Example screenshot ![Example Screen](githubdeveloperexample.png) 6. Copy the **Client ID** and _save it for later_ -7. Click **Generate a new client secret** and _save it for later_ You will not be able to see the secret again, so be sure to copy it now. +7. Click **Generate a new client secret** and _save it for later_ You will not be able to see the secret again, so be sure to copy it now. -## Authentik +## authentik 8. Under _Resources -> Sources_ Click **Create Github OAuth Source** @@ -49,7 +49,7 @@ As of June 20 2021 these URLS are correct. Here is the Github reference URL http 15. **Access token URL:** `https://github.com/login/oauth/access_token` 16. **Profile URL:** `https://api.github.com/user` -Here is an exmple of a complete Authentik Github OAuth Source +Here is an example of a complete authentik Github OAuth Source ![Example Screen](githubexample2.png) diff --git a/website/docs/integrations/sources/google/index.md b/website/docs/integrations/sources/google/index.md index 8fe7b550a..03f33e36d 100644 --- a/website/docs/integrations/sources/google/index.md +++ b/website/docs/integrations/sources/google/index.md @@ -15,7 +15,7 @@ The following placeholders will be used: You will need to create a new project, and OAuth credentials in the Google Developer console. The developer console can be overwhelming at first. 1. Visit https://console.developers.google.com/ to create a new project -2. Create a New project. +2. Create a New project. ![Example Screen](googledeveloper1.png) @@ -62,7 +62,7 @@ _I'm only going to list the mandatory/important fields to complete._ 24. Click **Create** 25. Copy and store _Your Client ID_ and _Your Client Secret_ for later -## Authentik +## authentik 26. Under _Resources -> Sources_ Click **Create Google OAuth Source** @@ -72,7 +72,7 @@ _I'm only going to list the mandatory/important fields to complete._ 30. **Consumer Secret:** Your Client Secret from step 25 31. **Provider Type:** Google -Here is an exmple of a complete Authentik Google OAuth Source +Here is an example of a complete authentik Google OAuth Source ![Example Screen](authentiksource.png) @@ -80,4 +80,4 @@ Save, and you now have Google as a source. :::note For more details on how-to have the new source display on the Login Page see the Sources page -::: \ No newline at end of file +::: diff --git a/website/docs/integrations/sources/plex/index.md b/website/docs/integrations/sources/plex/index.md index 23006ce49..ef1f523d6 100644 --- a/website/docs/integrations/sources/plex/index.md +++ b/website/docs/integrations/sources/plex/index.md @@ -8,7 +8,7 @@ Allows users to authenticate using their Plex credentials None -## Authentik -> Sources +## authentik -> Sources Add _Plex_ as a _source_ diff --git a/website/docs/providers/proxy/forward_auth.mdx b/website/docs/providers/proxy/forward_auth.mdx index 669e2aad9..b0ae3ac23 100644 --- a/website/docs/providers/proxy/forward_auth.mdx +++ b/website/docs/providers/proxy/forward_auth.mdx @@ -73,7 +73,7 @@ server { # authentik-specific config auth_request /akprox/auth/nginx; error_page 401 = @akprox_signin; - # For domain level, use the below error_page to redirect to your Authentik server with the full redirect path + # For domain level, use the below error_page to redirect to your authentik server with the full redirect path # error_page 401 =302 https://authentik.company/akprox/start?rd=$scheme://$http_host$request_uri; # translate headers from the outposts back to the actual upstream diff --git a/website/docs/releases/v0.10.md b/website/docs/releases/v0.10.md index 780af2c4b..4ba536734 100644 --- a/website/docs/releases/v0.10.md +++ b/website/docs/releases/v0.10.md @@ -69,7 +69,7 @@ error_reporting: ### Upgrading -This upgrade only applies if you are upgrading from a running 0.9 instance. Authentik detects this on startup, and automatically executes this upgrade. +This upgrade only applies if you are upgrading from a running 0.9 instance. authentik detects this on startup, and automatically executes this upgrade. Because this upgrade brings the new OAuth2 Provider, the old providers will be lost in the process. Make sure to take note of the providers you want to bring over. diff --git a/website/sidebars.js b/website/sidebars.js index a3593b3d8..3163bb35e 100644 --- a/website/sidebars.js +++ b/website/sidebars.js @@ -64,6 +64,7 @@ module.exports = { label: "as Source", items: [ "integrations/sources/index", + "integrations/sources/apple/index", "integrations/sources/active-directory/index", "integrations/sources/discord/index", "integrations/sources/github/index",