sources/oauth: add Twitch OAuth source (#3746)
* sources/oauth: add Twitch OAuth source Signed-off-by: Lukas Vögl <lukas@voegl.org> * website/integrations: add Twitch OAuth source documentation Signed-off-by: Lukas Vögl <lukas@voegl.org> Signed-off-by: Lukas Vögl <lukas@voegl.org>
This commit is contained in:
parent
a96b7dd9a3
commit
3ecc715e91
|
@ -17,6 +17,7 @@ AUTHENTIK_SOURCES_OAUTH_TYPES = [
|
|||
"authentik.sources.oauth.types.reddit",
|
||||
"authentik.sources.oauth.types.twitter",
|
||||
"authentik.sources.oauth.types.mailcow",
|
||||
"authentik.sources.oauth.types.twitch",
|
||||
]
|
||||
|
||||
|
||||
|
|
|
@ -115,6 +115,16 @@ class GitHubOAuthSource(OAuthSource):
|
|||
verbose_name_plural = _("GitHub OAuth Sources")
|
||||
|
||||
|
||||
class TwitchOAuthSource(OAuthSource):
|
||||
"""Social Login using Twitch."""
|
||||
|
||||
class Meta:
|
||||
|
||||
abstract = True
|
||||
verbose_name = _("Twitch OAuth Source")
|
||||
verbose_name_plural = _("Twitch OAuth Sources")
|
||||
|
||||
|
||||
class MailcowOAuthSource(OAuthSource):
|
||||
"""Social Login using Mailcow."""
|
||||
|
||||
|
|
37
authentik/sources/oauth/tests/test_type_twitch.py
Normal file
37
authentik/sources/oauth/tests/test_type_twitch.py
Normal file
|
@ -0,0 +1,37 @@
|
|||
"""Twitch Type tests"""
|
||||
from django.test import TestCase
|
||||
|
||||
from authentik.sources.oauth.models import OAuthSource
|
||||
from authentik.sources.oauth.types.twitch import TwitchOAuth2Callback
|
||||
|
||||
# https://dev.twitch.tv/docs/authentication/getting-tokens-oidc/#getting-claims-information-from-an-access-token
|
||||
TWITCH_USER = {
|
||||
"aud": "ym2tq9o71tikh2zyebksiture1hzg5",
|
||||
"exp": 1665261184,
|
||||
"iat": 1665260184,
|
||||
"iss": "https://id.twitch.tv/oauth2",
|
||||
"sub": "603916897",
|
||||
"email": "foo@bar.baz",
|
||||
"preferred_username": "FooBar",
|
||||
}
|
||||
|
||||
|
||||
class TestTypeTwitch(TestCase):
|
||||
"""OAuth Source tests"""
|
||||
|
||||
def setUp(self):
|
||||
self.source = OAuthSource.objects.create(
|
||||
name="test",
|
||||
slug="test",
|
||||
provider_type="twitch",
|
||||
authorization_url="",
|
||||
profile_url="",
|
||||
consumer_key="",
|
||||
)
|
||||
|
||||
def test_enroll_context(self):
|
||||
"""Test twitch Enrollment context"""
|
||||
ak_context = TwitchOAuth2Callback().get_user_enroll_context(TWITCH_USER)
|
||||
self.assertEqual(ak_context["username"], TWITCH_USER["preferred_username"])
|
||||
self.assertEqual(ak_context["email"], TWITCH_USER["email"])
|
||||
self.assertEqual(ak_context["name"], TWITCH_USER["preferred_username"])
|
60
authentik/sources/oauth/types/twitch.py
Normal file
60
authentik/sources/oauth/types/twitch.py
Normal file
|
@ -0,0 +1,60 @@
|
|||
"""Twitch OAuth Views"""
|
||||
from json import dumps
|
||||
from typing import Any, Optional
|
||||
|
||||
from authentik.sources.oauth.clients.oauth2 import UserprofileHeaderAuthClient
|
||||
from authentik.sources.oauth.types.registry import SourceType, registry
|
||||
from authentik.sources.oauth.views.callback import OAuthCallback
|
||||
from authentik.sources.oauth.views.redirect import OAuthRedirect
|
||||
|
||||
|
||||
class TwitchClient(UserprofileHeaderAuthClient):
|
||||
"""Twitch needs the token_type to be capitalized for the request header."""
|
||||
|
||||
def get_profile_info(self, token: dict[str, str]) -> Optional[dict[str, Any]]:
|
||||
token["token_type"] = token["token_type"].capitalize()
|
||||
return super().get_profile_info(token)
|
||||
|
||||
|
||||
class TwitchOAuthRedirect(OAuthRedirect):
|
||||
"""Twitch OAuth2 Redirect"""
|
||||
|
||||
def get_additional_parameters(self, source): # pragma: no cover
|
||||
claims = {"userinfo": {"email": None, "preferred_username": None}}
|
||||
return {
|
||||
"scope": ["openid"],
|
||||
"claims": dumps(claims),
|
||||
}
|
||||
|
||||
|
||||
class TwitchOAuth2Callback(OAuthCallback):
|
||||
"""Twitch OAuth2 Callback"""
|
||||
|
||||
client_class = TwitchClient
|
||||
|
||||
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("preferred_username"),
|
||||
"email": info.get("email"),
|
||||
"name": info.get("preferred_username"),
|
||||
}
|
||||
|
||||
|
||||
@registry.register()
|
||||
class TwitchType(SourceType):
|
||||
"""Twitch Type definition"""
|
||||
|
||||
callback_view = TwitchOAuth2Callback
|
||||
redirect_view = TwitchOAuthRedirect
|
||||
name = "Twitch"
|
||||
slug = "twitch"
|
||||
|
||||
authorization_url = "https://id.twitch.tv/oauth2/authorize"
|
||||
access_token_url = "https://id.twitch.tv/oauth2/token" # nosec
|
||||
profile_url = "https://id.twitch.tv/oauth2/userinfo"
|
|
@ -35104,6 +35104,7 @@ components:
|
|||
- reddit
|
||||
- twitter
|
||||
- mailcow
|
||||
- twitch
|
||||
type: string
|
||||
ProxyMode:
|
||||
enum:
|
||||
|
|
19
web/authentik/sources/twitch.svg
Normal file
19
web/authentik/sources/twitch.svg
Normal file
|
@ -0,0 +1,19 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- Generator: Adobe Illustrator 23.0.6, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 2400 2800" style="enable-background:new 0 0 2400 2800;" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
.st0{fill:#FFFFFF;}
|
||||
.st1{fill:#9146FF;}
|
||||
</style>
|
||||
<title>Asset 2</title>
|
||||
<g>
|
||||
<polygon class="st0" points="2200,1300 1800,1700 1400,1700 1050,2050 1050,1700 600,1700 600,200 2200,200 "/>
|
||||
<g>
|
||||
<g id="Layer_1-2">
|
||||
<path class="st1" d="M500,0L0,500v1800h600v500l500-500h400l900-900V0H500z M2200,1300l-400,400h-400l-350,350v-350H600V200h1600 V1300z"/>
|
||||
<rect x="1700" y="550" class="st1" width="200" height="600"/>
|
||||
<rect x="1150" y="550" class="st1" width="200" height="600"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 887 B |
60
website/integrations/sources/twitch/index.md
Normal file
60
website/integrations/sources/twitch/index.md
Normal file
|
@ -0,0 +1,60 @@
|
|||
---
|
||||
title: Twitch
|
||||
---
|
||||
|
||||
<span class="badge badge--secondary">Support level: Community</span>
|
||||
|
||||
Allows users to authenticate using their Twitch credentials
|
||||
|
||||
## Preparation
|
||||
|
||||
The following placeholders will be used:
|
||||
|
||||
- `authentik.company` is the FQDN of the authentik install.
|
||||
|
||||
## Twitch
|
||||
|
||||
1. Click **Register Your Application** in the Twitch Developers Console https://dev.twitch.tv/console
|
||||
|
||||
![Register Your Application Button](twitch1.png)
|
||||
|
||||
2. Name your Application
|
||||
|
||||
3. Add https://authentik.company/source/oauth/callback/twitch in the **OAuth Redirect URLs** field
|
||||
|
||||
4. Select a Category for your Application
|
||||
|
||||
5. Click **Create** to finish the registration of your Application
|
||||
|
||||
![Create Application](twitch2.png)
|
||||
|
||||
6. Click **Manage** on your newly created Application
|
||||
|
||||
![Manage Application](twitch3.png)
|
||||
|
||||
7. Copy your Client ID and save it for later
|
||||
|
||||
8. Click **New Secret** to create a new Secret
|
||||
|
||||
9. Copy the above Secret and also save it for later
|
||||
|
||||
![Copy Keys](twitch4.png)
|
||||
|
||||
## authentik
|
||||
|
||||
10. Under _Directory -> Federation & Social login_ Click **Create Twitch OAuth Source**
|
||||
|
||||
11. **Name:** Choose a name (For the example I used Twitch)
|
||||
12. **Slug:** twitch (You can choose a different slug, if you do you will need to update the Twitch redirect URL and point it to the correct slug.)
|
||||
13. **Consumer Key:** Client ID from step 7
|
||||
14. **Consumer Secret:** Secret from step 9
|
||||
|
||||
Here is an example of a complete authentik Twitch OAuth Source
|
||||
|
||||
![Authentik Source Example](twitch5.png)
|
||||
|
||||
Save, and you now have Twitch as a source.
|
||||
|
||||
:::note
|
||||
For more details on how-to have the new source display on the Login Page see [here](../).
|
||||
:::
|
BIN
website/integrations/sources/twitch/twitch1.png
Normal file
BIN
website/integrations/sources/twitch/twitch1.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 85 KiB |
BIN
website/integrations/sources/twitch/twitch2.png
Normal file
BIN
website/integrations/sources/twitch/twitch2.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 67 KiB |
BIN
website/integrations/sources/twitch/twitch3.png
Normal file
BIN
website/integrations/sources/twitch/twitch3.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 43 KiB |
BIN
website/integrations/sources/twitch/twitch4.png
Normal file
BIN
website/integrations/sources/twitch/twitch4.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 90 KiB |
BIN
website/integrations/sources/twitch/twitch5.png
Normal file
BIN
website/integrations/sources/twitch/twitch5.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 97 KiB |
|
@ -137,6 +137,7 @@ module.exports = {
|
|||
"sources/github/index",
|
||||
"sources/google/index",
|
||||
"sources/mailcow/index",
|
||||
"sources/twitch/index",
|
||||
"sources/plex/index",
|
||||
"sources/twitter/index",
|
||||
],
|
||||
|
|
Reference in a new issue