sources/oauth: add Sign in with Apple (#1635)
* sources/oauth: add apple sign in support Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org> * website/docs: apple sign in docs Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org> * website/docs: fix missing apple in sidebar Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org> * sources/oauth: add fallback values for name and slug Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
This commit is contained in:
parent
2c06eed8e7
commit
922fc9b8d5
|
@ -7,14 +7,15 @@ from structlog.stdlib import get_logger
|
||||||
LOGGER = get_logger()
|
LOGGER = get_logger()
|
||||||
|
|
||||||
AUTHENTIK_SOURCES_OAUTH_TYPES = [
|
AUTHENTIK_SOURCES_OAUTH_TYPES = [
|
||||||
|
"authentik.sources.oauth.types.apple",
|
||||||
|
"authentik.sources.oauth.types.azure_ad",
|
||||||
"authentik.sources.oauth.types.discord",
|
"authentik.sources.oauth.types.discord",
|
||||||
"authentik.sources.oauth.types.facebook",
|
"authentik.sources.oauth.types.facebook",
|
||||||
"authentik.sources.oauth.types.github",
|
"authentik.sources.oauth.types.github",
|
||||||
"authentik.sources.oauth.types.google",
|
"authentik.sources.oauth.types.google",
|
||||||
|
"authentik.sources.oauth.types.oidc",
|
||||||
"authentik.sources.oauth.types.reddit",
|
"authentik.sources.oauth.types.reddit",
|
||||||
"authentik.sources.oauth.types.twitter",
|
"authentik.sources.oauth.types.twitter",
|
||||||
"authentik.sources.oauth.types.azure_ad",
|
|
||||||
"authentik.sources.oauth.types.oidc",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
"""OAuth Clients"""
|
"""OAuth Clients"""
|
||||||
from typing import Any, Optional
|
from typing import Any, Optional
|
||||||
from urllib.parse import urlencode
|
from urllib.parse import quote, urlencode
|
||||||
|
|
||||||
from django.http import HttpRequest
|
from django.http import HttpRequest
|
||||||
from requests import Session
|
from requests import Session
|
||||||
|
@ -58,7 +58,7 @@ class BaseOAuthClient:
|
||||||
args = self.get_redirect_args()
|
args = self.get_redirect_args()
|
||||||
additional = parameters or {}
|
additional = parameters or {}
|
||||||
args.update(additional)
|
args.update(additional)
|
||||||
params = urlencode(args)
|
params = urlencode(args, quote_via=quote)
|
||||||
LOGGER.info("redirect args", **args)
|
LOGGER.info("redirect args", **args)
|
||||||
authorization_url = self.source.type.authorization_url or ""
|
authorization_url = self.source.type.authorization_url or ""
|
||||||
if self.source.type.urls_customizable and self.source.authorization_url:
|
if self.source.type.urls_customizable and self.source.authorization_url:
|
||||||
|
|
|
@ -20,10 +20,16 @@ class OAuth2Client(BaseOAuthClient):
|
||||||
"Accept": "application/json",
|
"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:
|
def check_application_state(self) -> bool:
|
||||||
"Check optional state parameter."
|
"Check optional state parameter."
|
||||||
stored = self.request.session.get(self.session_key, None)
|
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
|
check = False
|
||||||
if stored is not None:
|
if stored is not None:
|
||||||
if returned is not None:
|
if returned is not None:
|
||||||
|
@ -38,23 +44,31 @@ class OAuth2Client(BaseOAuthClient):
|
||||||
"Generate state optional parameter."
|
"Generate state optional parameter."
|
||||||
return get_random_string(32)
|
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]]:
|
def get_access_token(self, **request_kwargs) -> Optional[dict[str, Any]]:
|
||||||
"Fetch access token from callback request."
|
"Fetch access token from callback request."
|
||||||
callback = self.request.build_absolute_uri(self.callback or self.request.path)
|
callback = self.request.build_absolute_uri(self.callback or self.request.path)
|
||||||
if not self.check_application_state():
|
if not self.check_application_state():
|
||||||
LOGGER.warning("Application state check failed.")
|
LOGGER.warning("Application state check failed.")
|
||||||
return None
|
return None
|
||||||
if "code" in self.request.GET:
|
code = self.get_request_arg("code", None)
|
||||||
args = {
|
if not code:
|
||||||
"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:
|
|
||||||
LOGGER.warning("No code returned by the source")
|
LOGGER.warning("No code returned by the source")
|
||||||
return None
|
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:
|
try:
|
||||||
access_token_url = self.source.type.access_token_url or ""
|
access_token_url = self.source.type.access_token_url or ""
|
||||||
if self.source.type.urls_customizable and self.source.access_token_url:
|
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]:
|
def get_redirect_args(self) -> dict[str, str]:
|
||||||
"Get request parameters for redirect url."
|
"Get request parameters for redirect url."
|
||||||
callback = self.request.build_absolute_uri(self.callback)
|
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] = {
|
args: dict[str, str] = {
|
||||||
"client_id": client_id,
|
"client_id": client_id,
|
||||||
"redirect_uri": callback,
|
"redirect_uri": callback,
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
from typing import TYPE_CHECKING, Optional, Type
|
from typing import TYPE_CHECKING, Optional, Type
|
||||||
|
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.templatetags.static import static
|
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
from rest_framework.serializers import Serializer
|
from rest_framework.serializers import Serializer
|
||||||
|
@ -49,7 +48,7 @@ class OAuthSource(Source):
|
||||||
consumer_secret = models.TextField()
|
consumer_secret = models.TextField()
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def type(self) -> "SourceType":
|
def type(self) -> Type["SourceType"]:
|
||||||
"""Return the provider instance for this source"""
|
"""Return the provider instance for this source"""
|
||||||
from authentik.sources.oauth.types.manager import MANAGER
|
from authentik.sources.oauth.types.manager import MANAGER
|
||||||
|
|
||||||
|
@ -67,6 +66,7 @@ class OAuthSource(Source):
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def ui_login_button(self) -> UILoginButton:
|
def ui_login_button(self) -> UILoginButton:
|
||||||
|
provider_type = self.type
|
||||||
return UILoginButton(
|
return UILoginButton(
|
||||||
challenge=RedirectChallenge(
|
challenge=RedirectChallenge(
|
||||||
instance={
|
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,
|
name=self.name,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -173,6 +173,16 @@ class OpenIDConnectOAuthSource(OAuthSource):
|
||||||
verbose_name_plural = _("OpenID OAuth Sources")
|
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):
|
class UserOAuthSourceConnection(UserSourceConnection):
|
||||||
"""Authorized remote OAuth provider."""
|
"""Authorized remote OAuth provider."""
|
||||||
|
|
||||||
|
|
|
@ -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"
|
|
@ -1,7 +1,8 @@
|
||||||
"""Source type manager"""
|
"""Source type manager"""
|
||||||
from enum import Enum
|
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 structlog.stdlib import get_logger
|
||||||
|
|
||||||
from authentik.sources.oauth.views.callback import OAuthCallback
|
from authentik.sources.oauth.views.callback import OAuthCallback
|
||||||
|
@ -22,8 +23,8 @@ class SourceType:
|
||||||
|
|
||||||
callback_view = OAuthCallback
|
callback_view = OAuthCallback
|
||||||
redirect_view = OAuthRedirect
|
redirect_view = OAuthRedirect
|
||||||
name: str
|
name: str = "default"
|
||||||
slug: str
|
slug: str = "default"
|
||||||
|
|
||||||
urls_customizable = False
|
urls_customizable = False
|
||||||
|
|
||||||
|
@ -32,12 +33,16 @@ class SourceType:
|
||||||
access_token_url: Optional[str] = None
|
access_token_url: Optional[str] = None
|
||||||
profile_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:
|
class SourceTypeManager:
|
||||||
"""Manager to hold all Source types."""
|
"""Manager to hold all Source types."""
|
||||||
|
|
||||||
def __init__(self) -> None:
|
def __init__(self) -> None:
|
||||||
self.__sources: list[SourceType] = []
|
self.__sources: list[Type[SourceType]] = []
|
||||||
|
|
||||||
def type(self):
|
def type(self):
|
||||||
"""Class decorator to register classes inline."""
|
"""Class decorator to register classes inline."""
|
||||||
|
@ -56,14 +61,14 @@ class SourceTypeManager:
|
||||||
"""Get list of tuples of all registered names"""
|
"""Get list of tuples of all registered names"""
|
||||||
return [(x.slug, x.name) for x in self.__sources]
|
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"""
|
"""Find type based on source"""
|
||||||
found_type = None
|
found_type = None
|
||||||
for src_type in self.__sources:
|
for src_type in self.__sources:
|
||||||
if src_type.slug == type_name:
|
if src_type.slug == type_name:
|
||||||
return src_type
|
return src_type
|
||||||
if not found_type:
|
if not found_type:
|
||||||
found_type = SourceType()
|
found_type = SourceType
|
||||||
LOGGER.warning(
|
LOGGER.warning(
|
||||||
"no matching type found, using default",
|
"no matching type found, using default",
|
||||||
wanted=type_name,
|
wanted=type_name,
|
||||||
|
|
|
@ -24,7 +24,7 @@ class OAuthCallback(OAuthClientMixin, View):
|
||||||
source: OAuthSource
|
source: OAuthSource
|
||||||
|
|
||||||
# pylint: disable=too-many-return-statements
|
# pylint: disable=too-many-return-statements
|
||||||
def get(self, request: HttpRequest, *_, **kwargs) -> HttpResponse:
|
def dispatch(self, request: HttpRequest, *_, **kwargs) -> HttpResponse:
|
||||||
"""View Get handler"""
|
"""View Get handler"""
|
||||||
slug = kwargs.get("source_slug", "")
|
slug = kwargs.get("source_slug", "")
|
||||||
try:
|
try:
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
"""Dispatch OAuth views to respective views"""
|
"""Dispatch OAuth views to respective views"""
|
||||||
from django.shortcuts import get_object_or_404
|
from django.shortcuts import get_object_or_404
|
||||||
|
from django.utils.decorators import method_decorator
|
||||||
from django.views import View
|
from django.views import View
|
||||||
|
from django.views.decorators.csrf import csrf_exempt
|
||||||
from structlog.stdlib import get_logger
|
from structlog.stdlib import get_logger
|
||||||
|
|
||||||
from authentik.sources.oauth.models import OAuthSource
|
from authentik.sources.oauth.models import OAuthSource
|
||||||
|
@ -9,6 +11,7 @@ from authentik.sources.oauth.types.manager import MANAGER, RequestKind
|
||||||
LOGGER = get_logger()
|
LOGGER = get_logger()
|
||||||
|
|
||||||
|
|
||||||
|
@method_decorator(csrf_exempt, name="dispatch")
|
||||||
class DispatcherView(View):
|
class DispatcherView(View):
|
||||||
"""Dispatch OAuth Redirect/Callback views to their proper class based on URL parameters"""
|
"""Dispatch OAuth Redirect/Callback views to their proper class based on URL parameters"""
|
||||||
|
|
||||||
|
|
|
@ -119,7 +119,7 @@ class TestIdentificationStage(APITestCase):
|
||||||
"to": "/source/oauth/login/test/",
|
"to": "/source/oauth/login/test/",
|
||||||
"type": ChallengeTypes.REDIRECT.value,
|
"type": ChallengeTypes.REDIRECT.value,
|
||||||
},
|
},
|
||||||
"icon_url": "/static/authentik/sources/.svg",
|
"icon_url": "/static/authentik/sources/default.svg",
|
||||||
"name": "test",
|
"name": "test",
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
@ -170,7 +170,7 @@ class TestIdentificationStage(APITestCase):
|
||||||
"to": "/source/oauth/login/test/",
|
"to": "/source/oauth/login/test/",
|
||||||
"type": ChallengeTypes.REDIRECT.value,
|
"type": ChallengeTypes.REDIRECT.value,
|
||||||
},
|
},
|
||||||
"icon_url": "/static/authentik/sources/.svg",
|
"icon_url": "/static/authentik/sources/default.svg",
|
||||||
"name": "test",
|
"name": "test",
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
@ -226,7 +226,7 @@ class TestIdentificationStage(APITestCase):
|
||||||
},
|
},
|
||||||
"sources": [
|
"sources": [
|
||||||
{
|
{
|
||||||
"icon_url": "/static/authentik/sources/.svg",
|
"icon_url": "/static/authentik/sources/default.svg",
|
||||||
"name": "test",
|
"name": "test",
|
||||||
"challenge": {
|
"challenge": {
|
||||||
"component": "xak-flow-redirect",
|
"component": "xak-flow-redirect",
|
||||||
|
@ -280,7 +280,7 @@ class TestIdentificationStage(APITestCase):
|
||||||
"to": "/source/oauth/login/test/",
|
"to": "/source/oauth/login/test/",
|
||||||
"type": ChallengeTypes.REDIRECT.value,
|
"type": ChallengeTypes.REDIRECT.value,
|
||||||
},
|
},
|
||||||
"icon_url": "/static/authentik/sources/.svg",
|
"icon_url": "/static/authentik/sources/default.svg",
|
||||||
"name": "test",
|
"name": "test",
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
|
|
@ -8,7 +8,7 @@ msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: PACKAGE VERSION\n"
|
"Project-Id-Version: PACKAGE VERSION\n"
|
||||||
"Report-Msgid-Bugs-To: \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"
|
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||||
|
@ -308,6 +308,10 @@ msgstr ""
|
||||||
msgid "Notification Webhook Mappings"
|
msgid "Notification Webhook Mappings"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: authentik/events/monitored_tasks.py:122
|
||||||
|
msgid "Task has not been run yet."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: authentik/flows/api/flows.py:350
|
#: authentik/flows/api/flows.py:350
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Flow not applicable to current user/request: %(messages)s"
|
msgid "Flow not applicable to current user/request: %(messages)s"
|
||||||
|
@ -385,33 +389,33 @@ msgstr ""
|
||||||
msgid "Invalid kubeconfig"
|
msgid "Invalid kubeconfig"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: authentik/outposts/models.py:164
|
#: authentik/outposts/models.py:167
|
||||||
msgid "Outpost Service-Connection"
|
msgid "Outpost Service-Connection"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: authentik/outposts/models.py:165
|
#: authentik/outposts/models.py:168
|
||||||
msgid "Outpost Service-Connections"
|
msgid "Outpost Service-Connections"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: authentik/outposts/models.py:201
|
#: authentik/outposts/models.py:204
|
||||||
msgid ""
|
msgid ""
|
||||||
"Certificate/Key used for authentication. Can be left empty for no "
|
"Certificate/Key used for authentication. Can be left empty for no "
|
||||||
"authentication."
|
"authentication."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: authentik/outposts/models.py:243
|
#: authentik/outposts/models.py:246
|
||||||
msgid "Docker Service-Connection"
|
msgid "Docker Service-Connection"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: authentik/outposts/models.py:244
|
#: authentik/outposts/models.py:247
|
||||||
msgid "Docker Service-Connections"
|
msgid "Docker Service-Connections"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: authentik/outposts/models.py:290
|
#: authentik/outposts/models.py:293
|
||||||
msgid "Kubernetes Service-Connection"
|
msgid "Kubernetes Service-Connection"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: authentik/outposts/models.py:291
|
#: authentik/outposts/models.py:294
|
||||||
msgid "Kubernetes Service-Connections"
|
msgid "Kubernetes Service-Connections"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
@ -988,108 +992,116 @@ msgstr ""
|
||||||
msgid "Password does not match Active Directory Complexity."
|
msgid "Password does not match Active Directory Complexity."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: authentik/sources/oauth/models.py:25
|
#: authentik/sources/oauth/models.py:24
|
||||||
msgid "Request Token URL"
|
msgid "Request Token URL"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: authentik/sources/oauth/models.py:27
|
#: authentik/sources/oauth/models.py:26
|
||||||
msgid ""
|
msgid ""
|
||||||
"URL used to request the initial token. This URL is only required for OAuth 1."
|
"URL used to request the initial token. This URL is only required for OAuth 1."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: authentik/sources/oauth/models.py:33
|
#: authentik/sources/oauth/models.py:32
|
||||||
msgid "Authorization URL"
|
msgid "Authorization URL"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: authentik/sources/oauth/models.py:34
|
#: authentik/sources/oauth/models.py:33
|
||||||
msgid "URL the user is redirect to to conest the flow."
|
msgid "URL the user is redirect to to conest the flow."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: authentik/sources/oauth/models.py:39
|
#: authentik/sources/oauth/models.py:38
|
||||||
msgid "Access Token URL"
|
msgid "Access Token URL"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: authentik/sources/oauth/models.py:40
|
#: authentik/sources/oauth/models.py:39
|
||||||
msgid "URL used by authentik to retrieve tokens."
|
msgid "URL used by authentik to retrieve tokens."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: authentik/sources/oauth/models.py:45
|
#: authentik/sources/oauth/models.py:44
|
||||||
msgid "Profile URL"
|
msgid "Profile URL"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: authentik/sources/oauth/models.py:46
|
#: authentik/sources/oauth/models.py:45
|
||||||
msgid "URL used by authentik to get user information."
|
msgid "URL used by authentik to get user information."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: authentik/sources/oauth/models.py:102
|
#: authentik/sources/oauth/models.py:101
|
||||||
msgid "OAuth Source"
|
msgid "OAuth Source"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: authentik/sources/oauth/models.py:103
|
#: authentik/sources/oauth/models.py:102
|
||||||
msgid "OAuth Sources"
|
msgid "OAuth Sources"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: authentik/sources/oauth/models.py:112
|
#: authentik/sources/oauth/models.py:111
|
||||||
msgid "GitHub OAuth Source"
|
msgid "GitHub OAuth Source"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: authentik/sources/oauth/models.py:113
|
#: authentik/sources/oauth/models.py:112
|
||||||
msgid "GitHub OAuth Sources"
|
msgid "GitHub OAuth Sources"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: authentik/sources/oauth/models.py:122
|
#: authentik/sources/oauth/models.py:121
|
||||||
msgid "Twitter OAuth Source"
|
msgid "Twitter OAuth Source"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: authentik/sources/oauth/models.py:123
|
#: authentik/sources/oauth/models.py:122
|
||||||
msgid "Twitter OAuth Sources"
|
msgid "Twitter OAuth Sources"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: authentik/sources/oauth/models.py:132
|
#: authentik/sources/oauth/models.py:131
|
||||||
msgid "Facebook OAuth Source"
|
msgid "Facebook OAuth Source"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: authentik/sources/oauth/models.py:133
|
#: authentik/sources/oauth/models.py:132
|
||||||
msgid "Facebook OAuth Sources"
|
msgid "Facebook OAuth Sources"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: authentik/sources/oauth/models.py:142
|
#: authentik/sources/oauth/models.py:141
|
||||||
msgid "Discord OAuth Source"
|
msgid "Discord OAuth Source"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: authentik/sources/oauth/models.py:143
|
#: authentik/sources/oauth/models.py:142
|
||||||
msgid "Discord OAuth Sources"
|
msgid "Discord OAuth Sources"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: authentik/sources/oauth/models.py:152
|
#: authentik/sources/oauth/models.py:151
|
||||||
msgid "Google OAuth Source"
|
msgid "Google OAuth Source"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: authentik/sources/oauth/models.py:153
|
#: authentik/sources/oauth/models.py:152
|
||||||
msgid "Google OAuth Sources"
|
msgid "Google OAuth Sources"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: authentik/sources/oauth/models.py:162
|
#: authentik/sources/oauth/models.py:161
|
||||||
msgid "Azure AD OAuth Source"
|
msgid "Azure AD OAuth Source"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: authentik/sources/oauth/models.py:163
|
#: authentik/sources/oauth/models.py:162
|
||||||
msgid "Azure AD OAuth Sources"
|
msgid "Azure AD OAuth Sources"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: authentik/sources/oauth/models.py:172
|
#: authentik/sources/oauth/models.py:171
|
||||||
msgid "OpenID OAuth Source"
|
msgid "OpenID OAuth Source"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: authentik/sources/oauth/models.py:173
|
#: authentik/sources/oauth/models.py:172
|
||||||
msgid "OpenID OAuth Sources"
|
msgid "OpenID OAuth Sources"
|
||||||
msgstr ""
|
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"
|
msgid "User OAuth Source Connection"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: authentik/sources/oauth/models.py:189
|
#: authentik/sources/oauth/models.py:198
|
||||||
msgid "User OAuth Source Connections"
|
msgid "User OAuth Source Connections"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
@ -1214,19 +1226,19 @@ msgstr ""
|
||||||
msgid "Duo Devices"
|
msgid "Duo Devices"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: authentik/stages/authenticator_sms/models.py:97
|
#: authentik/stages/authenticator_sms/models.py:158
|
||||||
msgid "SMS Authenticator Setup Stage"
|
msgid "SMS Authenticator Setup Stage"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: authentik/stages/authenticator_sms/models.py:98
|
#: authentik/stages/authenticator_sms/models.py:159
|
||||||
msgid "SMS Authenticator Setup Stages"
|
msgid "SMS Authenticator Setup Stages"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: authentik/stages/authenticator_sms/models.py:116
|
#: authentik/stages/authenticator_sms/models.py:176
|
||||||
msgid "SMS Device"
|
msgid "SMS Device"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: authentik/stages/authenticator_sms/models.py:117
|
#: authentik/stages/authenticator_sms/models.py:177
|
||||||
msgid "SMS Devices"
|
msgid "SMS Devices"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
@ -1291,19 +1303,19 @@ msgstr ""
|
||||||
msgid "Authenticator Validation Stages"
|
msgid "Authenticator Validation Stages"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: authentik/stages/authenticator_webauthn/models.py:49
|
#: authentik/stages/authenticator_webauthn/models.py:51
|
||||||
msgid "WebAuthn Authenticator Setup Stage"
|
msgid "WebAuthn Authenticator Setup Stage"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: authentik/stages/authenticator_webauthn/models.py:50
|
#: authentik/stages/authenticator_webauthn/models.py:52
|
||||||
msgid "WebAuthn Authenticator Setup Stages"
|
msgid "WebAuthn Authenticator Setup Stages"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: authentik/stages/authenticator_webauthn/models.py:78
|
#: authentik/stages/authenticator_webauthn/models.py:85
|
||||||
msgid "WebAuthn Device"
|
msgid "WebAuthn Device"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: authentik/stages/authenticator_webauthn/models.py:79
|
#: authentik/stages/authenticator_webauthn/models.py:86
|
||||||
msgid "WebAuthn Devices"
|
msgid "WebAuthn Devices"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
|
|
@ -43,7 +43,7 @@ class OAUth1Type(SourceType):
|
||||||
urls_customizable = False
|
urls_customizable = False
|
||||||
|
|
||||||
|
|
||||||
SOURCE_TYPE_MOCK = Mock(return_value=OAUth1Type())
|
SOURCE_TYPE_MOCK = Mock(return_value=OAUth1Type)
|
||||||
|
|
||||||
|
|
||||||
@skipUnless(platform.startswith("linux"), "requires local docker")
|
@skipUnless(platform.startswith("linux"), "requires local docker")
|
||||||
|
|
|
@ -252,7 +252,7 @@ export class OAuthSourceForm extends ModelForm<OAuthSource, string> {
|
||||||
?writeOnly=${this.instance !== undefined}
|
?writeOnly=${this.instance !== undefined}
|
||||||
name="consumerSecret"
|
name="consumerSecret"
|
||||||
>
|
>
|
||||||
<input type="text" value="" class="pf-c-form-control" required />
|
<textarea class="pf-c-form-control"></textarea>
|
||||||
</ak-form-element-horizontal>
|
</ak-form-element-horizontal>
|
||||||
</div>
|
</div>
|
||||||
</ak-form-group>
|
</ak-form-group>
|
||||||
|
|
|
@ -50,7 +50,7 @@ In authentik, create an application which uses this provider. Optionally apply a
|
||||||
|
|
||||||
### Step 3
|
### Step 3
|
||||||
|
|
||||||
Obtain your Metadata URL from Authentik.
|
Obtain your Metadata URL from authentik.
|
||||||
|
|
||||||
1. Click on the BookStack Provider
|
1. Click on the BookStack Provider
|
||||||
2. Click the Metadata Tab
|
2. Click the Metadata Tab
|
||||||
|
@ -69,7 +69,7 @@ Modify the following Example SAML config and paste incorporate into your `.env`
|
||||||
AUTH_METHOD=saml2
|
AUTH_METHOD=saml2
|
||||||
# Set the display name to be shown on the login button.
|
# Set the display name to be shown on the login button.
|
||||||
# (Login with <name>)
|
# (Login with <name>)
|
||||||
SAML2_NAME=Authentik
|
SAML2_NAME=authentik
|
||||||
# Name of the attribute which provides the user's email address
|
# Name of the attribute which provides the user's email address
|
||||||
SAML2_EMAIL_ATTRIBUTE=email
|
SAML2_EMAIL_ATTRIBUTE=email
|
||||||
# Name of the attribute to use as an ID for the SAML user.
|
# Name of the attribute to use as an ID for the SAML user.
|
||||||
|
|
|
@ -21,7 +21,7 @@ The following placeholders will be used:
|
||||||
- `port.company` is the FQDN of Portainer.
|
- `port.company` is the FQDN of Portainer.
|
||||||
- `authentik.company` is the FQDN of authentik.
|
- `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:
|
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)
|
![](./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.
|
In authentik, create an application which uses this provider. Optionally apply access restrictions to the application using policy bindings.
|
||||||
|
|
||||||
|
|
|
@ -76,9 +76,9 @@ auth:
|
||||||
# The auth url to send users to if they want to authenticate using OpenID Connect.
|
# The auth url to send users to if they want to authenticate using OpenID Connect.
|
||||||
authurl: https://authentik.company/application/o/vikunja/
|
authurl: https://authentik.company/application/o/vikunja/
|
||||||
# The client ID used to authenticate Vikunja at the OpenID Connect provider.
|
# 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.
|
# 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
|
:::note
|
||||||
|
|
|
@ -39,7 +39,7 @@ import TabItem from '@theme/TabItem';
|
||||||
{label: 'Standalone', value: 'standalone'},
|
{label: 'Standalone', value: 'standalone'},
|
||||||
]}>
|
]}>
|
||||||
<TabItem value="docker">
|
<TabItem value="docker">
|
||||||
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
|
```yaml
|
||||||
environment:
|
environment:
|
||||||
|
@ -58,11 +58,11 @@ environment:
|
||||||
```
|
```
|
||||||
</TabItem>
|
</TabItem>
|
||||||
<TabItem value="standalone">
|
<TabItem value="standalone">
|
||||||
|
|
||||||
edit `.env` and add the following:
|
edit `.env` and add the following:
|
||||||
|
|
||||||
```ini
|
```ini
|
||||||
# Authentik OAUTH Config
|
# authentik OAUTH Config
|
||||||
OAUTH2_ENABLED='true'
|
OAUTH2_ENABLED='true'
|
||||||
OAUTH2_LOGIN_STYLE='redirect'
|
OAUTH2_LOGIN_STYLE='redirect'
|
||||||
OAUTH2_CLIENT_ID='<Client ID from above>'
|
OAUTH2_CLIENT_ID='<Client ID from above>'
|
||||||
|
|
|
@ -21,7 +21,7 @@ The following placeholders will be used:
|
||||||
- `wp.company` is the FQDN of Wordpress.
|
- `wp.company` is the FQDN of Wordpress.
|
||||||
- `authentik.company` is the FQDN of authentik.
|
- `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:
|
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_
|
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.
|
In authentik, create an application which uses this provider. Optionally apply access restrictions to the application using policy bindings.
|
||||||
|
|
||||||
|
|
Binary file not shown.
After Width: | Height: | Size: 62 KiB |
Binary file not shown.
After Width: | Height: | Size: 120 KiB |
|
@ -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.
|
||||||
|
:::
|
Binary file not shown.
After Width: | Height: | Size: 71 KiB |
Binary file not shown.
After Width: | Height: | Size: 53 KiB |
|
@ -33,7 +33,7 @@ Here is an example of a completed OAuth2 screen for Discord.
|
||||||
|
|
||||||
![Example Screen](discord4.png)
|
![Example Screen](discord4.png)
|
||||||
|
|
||||||
## Authentik
|
## authentik
|
||||||
|
|
||||||
8. Under _Resources -> Sources_ Click **Create Discord OAuth Source**
|
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
|
12. **Consumer Secret:** Client Secret from step 5
|
||||||
13. **Provider type:** Discord
|
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)
|
![Example Screen](discord5.png)
|
||||||
|
|
||||||
|
@ -51,4 +51,4 @@ Save, and you now have Discord as a source.
|
||||||
|
|
||||||
:::note
|
:::note
|
||||||
For more details on how-to have the new source display on the Login Page see the Sources page
|
For more details on how-to have the new source display on the Login Page see the Sources page
|
||||||
:::
|
:::
|
||||||
|
|
|
@ -17,7 +17,7 @@ The following placeholders will be used:
|
||||||
|
|
||||||
![Register OAuth App](githubdeveloper1.png)
|
![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
|
3. **Homepage URL**:: www.my.company
|
||||||
4. **Authorization callback URL**: https://authentik.company/source/oauth/callback/github
|
4. **Authorization callback URL**: https://authentik.company/source/oauth/callback/github
|
||||||
5. Click **Register Application**
|
5. Click **Register Application**
|
||||||
|
@ -27,9 +27,9 @@ Example screenshot
|
||||||
![Example Screen](githubdeveloperexample.png)
|
![Example Screen](githubdeveloperexample.png)
|
||||||
|
|
||||||
6. Copy the **Client ID** and _save it for later_
|
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**
|
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`
|
15. **Access token URL:** `https://github.com/login/oauth/access_token`
|
||||||
16. **Profile URL:** `https://api.github.com/user`
|
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)
|
![Example Screen](githubexample2.png)
|
||||||
|
|
||||||
|
|
|
@ -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.
|
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
|
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)
|
![Example Screen](googledeveloper1.png)
|
||||||
|
|
||||||
|
@ -62,7 +62,7 @@ _I'm only going to list the mandatory/important fields to complete._
|
||||||
24. Click **Create**
|
24. Click **Create**
|
||||||
25. Copy and store _Your Client ID_ and _Your Client Secret_ for later
|
25. Copy and store _Your Client ID_ and _Your Client Secret_ for later
|
||||||
|
|
||||||
## Authentik
|
## authentik
|
||||||
|
|
||||||
26. Under _Resources -> Sources_ Click **Create Google OAuth Source**
|
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
|
30. **Consumer Secret:** Your Client Secret from step 25
|
||||||
31. **Provider Type:** Google
|
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)
|
![Example Screen](authentiksource.png)
|
||||||
|
|
||||||
|
@ -80,4 +80,4 @@ Save, and you now have Google as a source.
|
||||||
|
|
||||||
:::note
|
:::note
|
||||||
For more details on how-to have the new source display on the Login Page see the Sources page
|
For more details on how-to have the new source display on the Login Page see the Sources page
|
||||||
:::
|
:::
|
||||||
|
|
|
@ -8,7 +8,7 @@ Allows users to authenticate using their Plex credentials
|
||||||
|
|
||||||
None
|
None
|
||||||
|
|
||||||
## Authentik -> Sources
|
## authentik -> Sources
|
||||||
|
|
||||||
Add _Plex_ as a _source_
|
Add _Plex_ as a _source_
|
||||||
|
|
||||||
|
|
|
@ -73,7 +73,7 @@ server {
|
||||||
# authentik-specific config
|
# authentik-specific config
|
||||||
auth_request /akprox/auth/nginx;
|
auth_request /akprox/auth/nginx;
|
||||||
error_page 401 = @akprox_signin;
|
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;
|
# 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
|
# translate headers from the outposts back to the actual upstream
|
||||||
|
|
|
@ -69,7 +69,7 @@ error_reporting:
|
||||||
|
|
||||||
### Upgrading
|
### 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.
|
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.
|
||||||
|
|
||||||
|
|
|
@ -64,6 +64,7 @@ module.exports = {
|
||||||
label: "as Source",
|
label: "as Source",
|
||||||
items: [
|
items: [
|
||||||
"integrations/sources/index",
|
"integrations/sources/index",
|
||||||
|
"integrations/sources/apple/index",
|
||||||
"integrations/sources/active-directory/index",
|
"integrations/sources/active-directory/index",
|
||||||
"integrations/sources/discord/index",
|
"integrations/sources/discord/index",
|
||||||
"integrations/sources/github/index",
|
"integrations/sources/github/index",
|
||||||
|
|
Reference in New Issue