providers/oauth2: add client_assertion_type jwt bearer support (#2618)
This commit is contained in:
		@ -36,6 +36,9 @@ from authentik.policies.models import PolicyBindingModel
 | 
				
			|||||||
LOGGER = get_logger()
 | 
					LOGGER = get_logger()
 | 
				
			||||||
USER_ATTRIBUTE_DEBUG = "goauthentik.io/user/debug"
 | 
					USER_ATTRIBUTE_DEBUG = "goauthentik.io/user/debug"
 | 
				
			||||||
USER_ATTRIBUTE_SA = "goauthentik.io/user/service-account"
 | 
					USER_ATTRIBUTE_SA = "goauthentik.io/user/service-account"
 | 
				
			||||||
 | 
					USER_ATTRIBUTE_GENERATED = "goauthentik.io/user/generated"
 | 
				
			||||||
 | 
					USER_ATTRIBUTE_EXPIRES = "goauthentik.io/user/expires"
 | 
				
			||||||
 | 
					USER_ATTRIBUTE_DELETE_ON_LOGOUT = "goauthentik.io/user/delete-on-logout"
 | 
				
			||||||
USER_ATTRIBUTE_SOURCES = "goauthentik.io/user/sources"
 | 
					USER_ATTRIBUTE_SOURCES = "goauthentik.io/user/sources"
 | 
				
			||||||
USER_ATTRIBUTE_TOKEN_EXPIRING = "goauthentik.io/user/token-expires"  # nosec
 | 
					USER_ATTRIBUTE_TOKEN_EXPIRING = "goauthentik.io/user/token-expires"  # nosec
 | 
				
			||||||
USER_ATTRIBUTE_CHANGE_USERNAME = "goauthentik.io/user/can-change-username"
 | 
					USER_ATTRIBUTE_CHANGE_USERNAME = "goauthentik.io/user/can-change-username"
 | 
				
			||||||
 | 
				
			|||||||
@ -1,10 +1,18 @@
 | 
				
			|||||||
"""authentik core tasks"""
 | 
					"""authentik core tasks"""
 | 
				
			||||||
 | 
					from datetime import datetime, timedelta
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from django.contrib.sessions.backends.cache import KEY_PREFIX
 | 
					from django.contrib.sessions.backends.cache import KEY_PREFIX
 | 
				
			||||||
from django.core.cache import cache
 | 
					from django.core.cache import cache
 | 
				
			||||||
from django.utils.timezone import now
 | 
					from django.utils.timezone import now
 | 
				
			||||||
from structlog.stdlib import get_logger
 | 
					from structlog.stdlib import get_logger
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from authentik.core.models import AuthenticatedSession, ExpiringModel
 | 
					from authentik.core.models import (
 | 
				
			||||||
 | 
					    USER_ATTRIBUTE_EXPIRES,
 | 
				
			||||||
 | 
					    USER_ATTRIBUTE_GENERATED,
 | 
				
			||||||
 | 
					    AuthenticatedSession,
 | 
				
			||||||
 | 
					    ExpiringModel,
 | 
				
			||||||
 | 
					    User,
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
from authentik.events.monitored_tasks import (
 | 
					from authentik.events.monitored_tasks import (
 | 
				
			||||||
    MonitoredTask,
 | 
					    MonitoredTask,
 | 
				
			||||||
    TaskResult,
 | 
					    TaskResult,
 | 
				
			||||||
@ -42,3 +50,22 @@ def clean_expired_models(self: MonitoredTask):
 | 
				
			|||||||
    LOGGER.debug("Expired sessions", model=AuthenticatedSession, amount=amount)
 | 
					    LOGGER.debug("Expired sessions", model=AuthenticatedSession, amount=amount)
 | 
				
			||||||
    messages.append(f"Expired {amount} {AuthenticatedSession._meta.verbose_name_plural}")
 | 
					    messages.append(f"Expired {amount} {AuthenticatedSession._meta.verbose_name_plural}")
 | 
				
			||||||
    self.set_status(TaskResult(TaskResultStatus.SUCCESSFUL, messages))
 | 
					    self.set_status(TaskResult(TaskResultStatus.SUCCESSFUL, messages))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@CELERY_APP.task(bind=True, base=MonitoredTask)
 | 
				
			||||||
 | 
					@prefill_task
 | 
				
			||||||
 | 
					def clean_temporary_users(self: MonitoredTask):
 | 
				
			||||||
 | 
					    """Remove temporary users created by SAML Sources"""
 | 
				
			||||||
 | 
					    _now = datetime.now()
 | 
				
			||||||
 | 
					    messages = []
 | 
				
			||||||
 | 
					    deleted_users = 0
 | 
				
			||||||
 | 
					    for user in User.objects.filter(**{f"attributes__{USER_ATTRIBUTE_GENERATED}": True}):
 | 
				
			||||||
 | 
					        delta: timedelta = _now - datetime.fromtimestamp(
 | 
				
			||||||
 | 
					            user.attributes.get(USER_ATTRIBUTE_EXPIRES)
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        if delta.total_seconds() > 0:
 | 
				
			||||||
 | 
					            LOGGER.debug("User is expired and will be deleted.", user=user, delta=delta)
 | 
				
			||||||
 | 
					            user.delete()
 | 
				
			||||||
 | 
					            deleted_users += 1
 | 
				
			||||||
 | 
					    messages.append(f"Successfully deleted {deleted_users} users.")
 | 
				
			||||||
 | 
					    self.set_status(TaskResult(TaskResultStatus.SUCCESSFUL, messages))
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										50
									
								
								authentik/core/tests/test_tasks.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										50
									
								
								authentik/core/tests/test_tasks.py
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,50 @@
 | 
				
			|||||||
 | 
					"""Test tasks"""
 | 
				
			||||||
 | 
					from time import mktime
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from django.utils.timezone import now
 | 
				
			||||||
 | 
					from guardian.shortcuts import get_anonymous_user
 | 
				
			||||||
 | 
					from rest_framework.test import APITestCase
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from authentik.core.models import (
 | 
				
			||||||
 | 
					    USER_ATTRIBUTE_EXPIRES,
 | 
				
			||||||
 | 
					    USER_ATTRIBUTE_GENERATED,
 | 
				
			||||||
 | 
					    Token,
 | 
				
			||||||
 | 
					    TokenIntents,
 | 
				
			||||||
 | 
					    User,
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					from authentik.core.tasks import clean_expired_models, clean_temporary_users
 | 
				
			||||||
 | 
					from authentik.core.tests.utils import create_test_admin_user
 | 
				
			||||||
 | 
					from authentik.lib.generators import generate_id
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class TestTasks(APITestCase):
 | 
				
			||||||
 | 
					    """Test token API"""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def setUp(self) -> None:
 | 
				
			||||||
 | 
					        super().setUp()
 | 
				
			||||||
 | 
					        self.user = User.objects.create(username="testuser")
 | 
				
			||||||
 | 
					        self.admin = create_test_admin_user()
 | 
				
			||||||
 | 
					        self.client.force_login(self.user)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_token_expire(self):
 | 
				
			||||||
 | 
					        """Test Token expire task"""
 | 
				
			||||||
 | 
					        token: Token = Token.objects.create(
 | 
				
			||||||
 | 
					            expires=now(), user=get_anonymous_user(), intent=TokenIntents.INTENT_API
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        key = token.key
 | 
				
			||||||
 | 
					        clean_expired_models.delay().get()
 | 
				
			||||||
 | 
					        token.refresh_from_db()
 | 
				
			||||||
 | 
					        self.assertNotEqual(key, token.key)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_clean_temporary_users(self):
 | 
				
			||||||
 | 
					        """Test clean_temporary_users task"""
 | 
				
			||||||
 | 
					        username = generate_id
 | 
				
			||||||
 | 
					        User.objects.create(
 | 
				
			||||||
 | 
					            username=username,
 | 
				
			||||||
 | 
					            attributes={
 | 
				
			||||||
 | 
					                USER_ATTRIBUTE_GENERATED: True,
 | 
				
			||||||
 | 
					                USER_ATTRIBUTE_EXPIRES: mktime(now().timetuple()),
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        clean_temporary_users.delay().get()
 | 
				
			||||||
 | 
					        self.assertFalse(User.objects.filter(username=username))
 | 
				
			||||||
@ -2,12 +2,10 @@
 | 
				
			|||||||
from json import loads
 | 
					from json import loads
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from django.urls.base import reverse
 | 
					from django.urls.base import reverse
 | 
				
			||||||
from django.utils.timezone import now
 | 
					 | 
				
			||||||
from guardian.shortcuts import get_anonymous_user
 | 
					from guardian.shortcuts import get_anonymous_user
 | 
				
			||||||
from rest_framework.test import APITestCase
 | 
					from rest_framework.test import APITestCase
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from authentik.core.models import USER_ATTRIBUTE_TOKEN_EXPIRING, Token, TokenIntents, User
 | 
					from authentik.core.models import USER_ATTRIBUTE_TOKEN_EXPIRING, Token, TokenIntents, User
 | 
				
			||||||
from authentik.core.tasks import clean_expired_models
 | 
					 | 
				
			||||||
from authentik.core.tests.utils import create_test_admin_user
 | 
					from authentik.core.tests.utils import create_test_admin_user
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -53,16 +51,6 @@ class TestTokenAPI(APITestCase):
 | 
				
			|||||||
        self.assertEqual(token.intent, TokenIntents.INTENT_API)
 | 
					        self.assertEqual(token.intent, TokenIntents.INTENT_API)
 | 
				
			||||||
        self.assertEqual(token.expiring, False)
 | 
					        self.assertEqual(token.expiring, False)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_token_expire(self):
 | 
					 | 
				
			||||||
        """Test Token expire task"""
 | 
					 | 
				
			||||||
        token: Token = Token.objects.create(
 | 
					 | 
				
			||||||
            expires=now(), user=get_anonymous_user(), intent=TokenIntents.INTENT_API
 | 
					 | 
				
			||||||
        )
 | 
					 | 
				
			||||||
        key = token.key
 | 
					 | 
				
			||||||
        clean_expired_models.delay().get()
 | 
					 | 
				
			||||||
        token.refresh_from_db()
 | 
					 | 
				
			||||||
        self.assertNotEqual(key, token.key)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def test_list(self):
 | 
					    def test_list(self):
 | 
				
			||||||
        """Test Token List (Test normal authentication)"""
 | 
					        """Test Token List (Test normal authentication)"""
 | 
				
			||||||
        token_should: Token = Token.objects.create(
 | 
					        token_should: Token = Token.objects.create(
 | 
				
			||||||
 | 
				
			|||||||
@ -34,6 +34,7 @@ class OAuth2ProviderSerializer(ProviderSerializer):
 | 
				
			|||||||
            "sub_mode",
 | 
					            "sub_mode",
 | 
				
			||||||
            "property_mappings",
 | 
					            "property_mappings",
 | 
				
			||||||
            "issuer_mode",
 | 
					            "issuer_mode",
 | 
				
			||||||
 | 
					            "verification_keys",
 | 
				
			||||||
        ]
 | 
					        ]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -4,6 +4,10 @@ GRANT_TYPE_AUTHORIZATION_CODE = "authorization_code"
 | 
				
			|||||||
GRANT_TYPE_REFRESH_TOKEN = "refresh_token"  # nosec
 | 
					GRANT_TYPE_REFRESH_TOKEN = "refresh_token"  # nosec
 | 
				
			||||||
GRANT_TYPE_CLIENT_CREDENTIALS = "client_credentials"
 | 
					GRANT_TYPE_CLIENT_CREDENTIALS = "client_credentials"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					CLIENT_ASSERTION_TYPE = "client_assertion_type"
 | 
				
			||||||
 | 
					CLIENT_ASSERTION = "client_assertion"
 | 
				
			||||||
 | 
					CLIENT_ASSERTION_TYPE_JWT = "urn:ietf:params:oauth:client-assertion-type:jwt-bearer"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
PROMPT_NONE = "none"
 | 
					PROMPT_NONE = "none"
 | 
				
			||||||
PROMPT_CONSNET = "consent"
 | 
					PROMPT_CONSNET = "consent"
 | 
				
			||||||
PROMPT_LOGIN = "login"
 | 
					PROMPT_LOGIN = "login"
 | 
				
			||||||
 | 
				
			|||||||
@ -0,0 +1,36 @@
 | 
				
			|||||||
 | 
					# Generated by Django 4.0.3 on 2022-03-29 19:37
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import django.db.models.deletion
 | 
				
			||||||
 | 
					from django.db import migrations, models
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Migration(migrations.Migration):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    dependencies = [
 | 
				
			||||||
 | 
					        ("authentik_crypto", "0003_certificatekeypair_managed"),
 | 
				
			||||||
 | 
					        ("authentik_providers_oauth2", "0008_rename_rsa_key_oauth2provider_signing_key_and_more"),
 | 
				
			||||||
 | 
					    ]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    operations = [
 | 
				
			||||||
 | 
					        migrations.AddField(
 | 
				
			||||||
 | 
					            model_name="oauth2provider",
 | 
				
			||||||
 | 
					            name="verification_keys",
 | 
				
			||||||
 | 
					            field=models.ManyToManyField(
 | 
				
			||||||
 | 
					                help_text="JWTs created with the configured certificates can authenticate with this provider.",
 | 
				
			||||||
 | 
					                related_name="+",
 | 
				
			||||||
 | 
					                to="authentik_crypto.certificatekeypair",
 | 
				
			||||||
 | 
					                verbose_name="Allowed certificates for JWT-based client_credentials",
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					        migrations.AlterField(
 | 
				
			||||||
 | 
					            model_name="oauth2provider",
 | 
				
			||||||
 | 
					            name="signing_key",
 | 
				
			||||||
 | 
					            field=models.ForeignKey(
 | 
				
			||||||
 | 
					                help_text="Key used to sign the tokens. Only required when JWT Algorithm is set to RS256.",
 | 
				
			||||||
 | 
					                null=True,
 | 
				
			||||||
 | 
					                on_delete=django.db.models.deletion.SET_NULL,
 | 
				
			||||||
 | 
					                to="authentik_crypto.certificatekeypair",
 | 
				
			||||||
 | 
					                verbose_name="Signing Key",
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					    ]
 | 
				
			||||||
@ -212,7 +212,7 @@ class OAuth2Provider(Provider):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    signing_key = models.ForeignKey(
 | 
					    signing_key = models.ForeignKey(
 | 
				
			||||||
        CertificateKeyPair,
 | 
					        CertificateKeyPair,
 | 
				
			||||||
        verbose_name=_("RSA Key"),
 | 
					        verbose_name=_("Signing Key"),
 | 
				
			||||||
        on_delete=models.SET_NULL,
 | 
					        on_delete=models.SET_NULL,
 | 
				
			||||||
        null=True,
 | 
					        null=True,
 | 
				
			||||||
        help_text=_(
 | 
					        help_text=_(
 | 
				
			||||||
@ -220,6 +220,15 @@ class OAuth2Provider(Provider):
 | 
				
			|||||||
        ),
 | 
					        ),
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    verification_keys = models.ManyToManyField(
 | 
				
			||||||
 | 
					        CertificateKeyPair,
 | 
				
			||||||
 | 
					        verbose_name=_("Allowed certificates for JWT-based client_credentials"),
 | 
				
			||||||
 | 
					        help_text=_(
 | 
				
			||||||
 | 
					            "JWTs created with the configured certificates can authenticate with this provider."
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					        related_name="+",
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def create_refresh_token(
 | 
					    def create_refresh_token(
 | 
				
			||||||
        self, user: User, scope: list[str], request: HttpRequest
 | 
					        self, user: User, scope: list[str], request: HttpRequest
 | 
				
			||||||
    ) -> "RefreshToken":
 | 
					    ) -> "RefreshToken":
 | 
				
			||||||
 | 
				
			|||||||
@ -0,0 +1,206 @@
 | 
				
			|||||||
 | 
					"""Test token view"""
 | 
				
			||||||
 | 
					from datetime import datetime, timedelta
 | 
				
			||||||
 | 
					from json import loads
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from django.test import RequestFactory
 | 
				
			||||||
 | 
					from django.urls import reverse
 | 
				
			||||||
 | 
					from jwt import decode
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from authentik.core.models import USER_ATTRIBUTE_SA, Application, Group
 | 
				
			||||||
 | 
					from authentik.core.tests.utils import create_test_admin_user, create_test_cert, create_test_flow
 | 
				
			||||||
 | 
					from authentik.lib.generators import generate_id, generate_key
 | 
				
			||||||
 | 
					from authentik.managed.manager import ObjectManager
 | 
				
			||||||
 | 
					from authentik.policies.models import PolicyBinding
 | 
				
			||||||
 | 
					from authentik.providers.oauth2.constants import (
 | 
				
			||||||
 | 
					    GRANT_TYPE_CLIENT_CREDENTIALS,
 | 
				
			||||||
 | 
					    SCOPE_OPENID,
 | 
				
			||||||
 | 
					    SCOPE_OPENID_EMAIL,
 | 
				
			||||||
 | 
					    SCOPE_OPENID_PROFILE,
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					from authentik.providers.oauth2.models import OAuth2Provider, ScopeMapping
 | 
				
			||||||
 | 
					from authentik.providers.oauth2.tests.utils import OAuthTestCase
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class TestTokenClientCredentialsJWT(OAuthTestCase):
 | 
				
			||||||
 | 
					    """Test token (client_credentials, with JWT) view"""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def setUp(self) -> None:
 | 
				
			||||||
 | 
					        super().setUp()
 | 
				
			||||||
 | 
					        ObjectManager().run()
 | 
				
			||||||
 | 
					        self.factory = RequestFactory()
 | 
				
			||||||
 | 
					        self.cert = create_test_cert()
 | 
				
			||||||
 | 
					        self.provider: OAuth2Provider = OAuth2Provider.objects.create(
 | 
				
			||||||
 | 
					            name="test",
 | 
				
			||||||
 | 
					            client_id=generate_id(),
 | 
				
			||||||
 | 
					            client_secret=generate_key(),
 | 
				
			||||||
 | 
					            authorization_flow=create_test_flow(),
 | 
				
			||||||
 | 
					            redirect_uris="http://testserver",
 | 
				
			||||||
 | 
					            signing_key=self.cert,
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        self.provider.verification_keys.set([self.cert])
 | 
				
			||||||
 | 
					        self.provider.property_mappings.set(ScopeMapping.objects.all())
 | 
				
			||||||
 | 
					        self.app = Application.objects.create(name="test", slug="test", provider=self.provider)
 | 
				
			||||||
 | 
					        self.user = create_test_admin_user("sa")
 | 
				
			||||||
 | 
					        self.user.attributes[USER_ATTRIBUTE_SA] = True
 | 
				
			||||||
 | 
					        self.user.save()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_invalid_type(self):
 | 
				
			||||||
 | 
					        """test invalid type"""
 | 
				
			||||||
 | 
					        response = self.client.post(
 | 
				
			||||||
 | 
					            reverse("authentik_providers_oauth2:token"),
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                "grant_type": GRANT_TYPE_CLIENT_CREDENTIALS,
 | 
				
			||||||
 | 
					                "scope": f"{SCOPE_OPENID} {SCOPE_OPENID_EMAIL} {SCOPE_OPENID_PROFILE}",
 | 
				
			||||||
 | 
					                "client_id": self.provider.client_id,
 | 
				
			||||||
 | 
					                "client_assertion_type": "foo",
 | 
				
			||||||
 | 
					                "client_assertion": "foo.bar",
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        self.assertEqual(response.status_code, 400)
 | 
				
			||||||
 | 
					        body = loads(response.content.decode())
 | 
				
			||||||
 | 
					        self.assertEqual(body["error"], "invalid_grant")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_invalid_jwt(self):
 | 
				
			||||||
 | 
					        """test invalid JWT"""
 | 
				
			||||||
 | 
					        response = self.client.post(
 | 
				
			||||||
 | 
					            reverse("authentik_providers_oauth2:token"),
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                "grant_type": GRANT_TYPE_CLIENT_CREDENTIALS,
 | 
				
			||||||
 | 
					                "scope": f"{SCOPE_OPENID} {SCOPE_OPENID_EMAIL} {SCOPE_OPENID_PROFILE}",
 | 
				
			||||||
 | 
					                "client_id": self.provider.client_id,
 | 
				
			||||||
 | 
					                "client_assertion_type": "urn:ietf:params:oauth:client-assertion-type:jwt-bearer",
 | 
				
			||||||
 | 
					                "client_assertion": "foo.bar",
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        self.assertEqual(response.status_code, 400)
 | 
				
			||||||
 | 
					        body = loads(response.content.decode())
 | 
				
			||||||
 | 
					        self.assertEqual(body["error"], "invalid_grant")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_invalid_signautre(self):
 | 
				
			||||||
 | 
					        """test invalid JWT"""
 | 
				
			||||||
 | 
					        token = self.provider.encode(
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                "sub": "foo",
 | 
				
			||||||
 | 
					                "exp": datetime.now() + timedelta(hours=2),
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        response = self.client.post(
 | 
				
			||||||
 | 
					            reverse("authentik_providers_oauth2:token"),
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                "grant_type": GRANT_TYPE_CLIENT_CREDENTIALS,
 | 
				
			||||||
 | 
					                "scope": f"{SCOPE_OPENID} {SCOPE_OPENID_EMAIL} {SCOPE_OPENID_PROFILE}",
 | 
				
			||||||
 | 
					                "client_id": self.provider.client_id,
 | 
				
			||||||
 | 
					                "client_assertion_type": "urn:ietf:params:oauth:client-assertion-type:jwt-bearer",
 | 
				
			||||||
 | 
					                "client_assertion": token + "foo",
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        self.assertEqual(response.status_code, 400)
 | 
				
			||||||
 | 
					        body = loads(response.content.decode())
 | 
				
			||||||
 | 
					        self.assertEqual(body["error"], "invalid_grant")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_invalid_expired(self):
 | 
				
			||||||
 | 
					        """test invalid JWT"""
 | 
				
			||||||
 | 
					        token = self.provider.encode(
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                "sub": "foo",
 | 
				
			||||||
 | 
					                "exp": datetime.now() - timedelta(hours=2),
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        response = self.client.post(
 | 
				
			||||||
 | 
					            reverse("authentik_providers_oauth2:token"),
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                "grant_type": GRANT_TYPE_CLIENT_CREDENTIALS,
 | 
				
			||||||
 | 
					                "scope": f"{SCOPE_OPENID} {SCOPE_OPENID_EMAIL} {SCOPE_OPENID_PROFILE}",
 | 
				
			||||||
 | 
					                "client_id": self.provider.client_id,
 | 
				
			||||||
 | 
					                "client_assertion_type": "urn:ietf:params:oauth:client-assertion-type:jwt-bearer",
 | 
				
			||||||
 | 
					                "client_assertion": token,
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        self.assertEqual(response.status_code, 400)
 | 
				
			||||||
 | 
					        body = loads(response.content.decode())
 | 
				
			||||||
 | 
					        self.assertEqual(body["error"], "invalid_grant")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_invalid_no_app(self):
 | 
				
			||||||
 | 
					        """test invalid JWT"""
 | 
				
			||||||
 | 
					        self.app.provider = None
 | 
				
			||||||
 | 
					        self.app.save()
 | 
				
			||||||
 | 
					        token = self.provider.encode(
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                "sub": "foo",
 | 
				
			||||||
 | 
					                "exp": datetime.now() + timedelta(hours=2),
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        response = self.client.post(
 | 
				
			||||||
 | 
					            reverse("authentik_providers_oauth2:token"),
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                "grant_type": GRANT_TYPE_CLIENT_CREDENTIALS,
 | 
				
			||||||
 | 
					                "scope": f"{SCOPE_OPENID} {SCOPE_OPENID_EMAIL} {SCOPE_OPENID_PROFILE}",
 | 
				
			||||||
 | 
					                "client_id": self.provider.client_id,
 | 
				
			||||||
 | 
					                "client_assertion_type": "urn:ietf:params:oauth:client-assertion-type:jwt-bearer",
 | 
				
			||||||
 | 
					                "client_assertion": token,
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        self.assertEqual(response.status_code, 400)
 | 
				
			||||||
 | 
					        body = loads(response.content.decode())
 | 
				
			||||||
 | 
					        self.assertEqual(body["error"], "invalid_grant")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_invalid_access_denied(self):
 | 
				
			||||||
 | 
					        """test invalid JWT"""
 | 
				
			||||||
 | 
					        group = Group.objects.create(name="foo")
 | 
				
			||||||
 | 
					        PolicyBinding.objects.create(
 | 
				
			||||||
 | 
					            group=group,
 | 
				
			||||||
 | 
					            target=self.app,
 | 
				
			||||||
 | 
					            order=0,
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        token = self.provider.encode(
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                "sub": "foo",
 | 
				
			||||||
 | 
					                "exp": datetime.now() + timedelta(hours=2),
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        response = self.client.post(
 | 
				
			||||||
 | 
					            reverse("authentik_providers_oauth2:token"),
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                "grant_type": GRANT_TYPE_CLIENT_CREDENTIALS,
 | 
				
			||||||
 | 
					                "scope": f"{SCOPE_OPENID} {SCOPE_OPENID_EMAIL} {SCOPE_OPENID_PROFILE}",
 | 
				
			||||||
 | 
					                "client_id": self.provider.client_id,
 | 
				
			||||||
 | 
					                "client_assertion_type": "urn:ietf:params:oauth:client-assertion-type:jwt-bearer",
 | 
				
			||||||
 | 
					                "client_assertion": token,
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        self.assertEqual(response.status_code, 400)
 | 
				
			||||||
 | 
					        body = loads(response.content.decode())
 | 
				
			||||||
 | 
					        self.assertEqual(body["error"], "invalid_grant")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_successful(self):
 | 
				
			||||||
 | 
					        """test successful"""
 | 
				
			||||||
 | 
					        token = self.provider.encode(
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                "sub": "foo",
 | 
				
			||||||
 | 
					                "exp": datetime.now() + timedelta(hours=2),
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        response = self.client.post(
 | 
				
			||||||
 | 
					            reverse("authentik_providers_oauth2:token"),
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                "grant_type": GRANT_TYPE_CLIENT_CREDENTIALS,
 | 
				
			||||||
 | 
					                "scope": f"{SCOPE_OPENID} {SCOPE_OPENID_EMAIL} {SCOPE_OPENID_PROFILE}",
 | 
				
			||||||
 | 
					                "client_id": self.provider.client_id,
 | 
				
			||||||
 | 
					                "client_assertion_type": "urn:ietf:params:oauth:client-assertion-type:jwt-bearer",
 | 
				
			||||||
 | 
					                "client_assertion": token,
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        self.assertEqual(response.status_code, 200)
 | 
				
			||||||
 | 
					        body = loads(response.content.decode())
 | 
				
			||||||
 | 
					        self.assertEqual(body["token_type"], "bearer")
 | 
				
			||||||
 | 
					        _, alg = self.provider.get_jwt_key()
 | 
				
			||||||
 | 
					        jwt = decode(
 | 
				
			||||||
 | 
					            body["access_token"],
 | 
				
			||||||
 | 
					            key=self.provider.signing_key.public_key,
 | 
				
			||||||
 | 
					            algorithms=[alg],
 | 
				
			||||||
 | 
					            audience=self.provider.client_id,
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        self.assertEqual(
 | 
				
			||||||
 | 
					            jwt["given_name"], "Autogenerated user from application test (client credentials JWT)"
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        self.assertEqual(jwt["preferred_username"], "test-foo")
 | 
				
			||||||
@ -36,7 +36,6 @@ class JWKSView(View):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        if signing_key:
 | 
					        if signing_key:
 | 
				
			||||||
            private_key = signing_key.private_key
 | 
					            private_key = signing_key.private_key
 | 
				
			||||||
            print(type(private_key))
 | 
					 | 
				
			||||||
            if isinstance(private_key, RSAPrivateKey):
 | 
					            if isinstance(private_key, RSAPrivateKey):
 | 
				
			||||||
                public_key: RSAPublicKey = private_key.public_key()
 | 
					                public_key: RSAPublicKey = private_key.public_key()
 | 
				
			||||||
                public_numbers = public_key.public_numbers()
 | 
					                public_numbers = public_key.public_numbers()
 | 
				
			||||||
 | 
				
			|||||||
@ -5,14 +5,27 @@ from hashlib import sha256
 | 
				
			|||||||
from typing import Any, Optional
 | 
					from typing import Any, Optional
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from django.http import HttpRequest, HttpResponse
 | 
					from django.http import HttpRequest, HttpResponse
 | 
				
			||||||
 | 
					from django.utils.timezone import datetime, now
 | 
				
			||||||
from django.views import View
 | 
					from django.views import View
 | 
				
			||||||
 | 
					from jwt import InvalidTokenError, decode
 | 
				
			||||||
from structlog.stdlib import get_logger
 | 
					from structlog.stdlib import get_logger
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from authentik.core.models import USER_ATTRIBUTE_SA, Application, Token, TokenIntents, User
 | 
					from authentik.core.models import (
 | 
				
			||||||
 | 
					    USER_ATTRIBUTE_EXPIRES,
 | 
				
			||||||
 | 
					    USER_ATTRIBUTE_GENERATED,
 | 
				
			||||||
 | 
					    USER_ATTRIBUTE_SA,
 | 
				
			||||||
 | 
					    Application,
 | 
				
			||||||
 | 
					    Token,
 | 
				
			||||||
 | 
					    TokenIntents,
 | 
				
			||||||
 | 
					    User,
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
from authentik.events.models import Event, EventAction
 | 
					from authentik.events.models import Event, EventAction
 | 
				
			||||||
from authentik.lib.utils.time import timedelta_from_string
 | 
					from authentik.lib.utils.time import timedelta_from_string
 | 
				
			||||||
from authentik.policies.engine import PolicyEngine
 | 
					from authentik.policies.engine import PolicyEngine
 | 
				
			||||||
from authentik.providers.oauth2.constants import (
 | 
					from authentik.providers.oauth2.constants import (
 | 
				
			||||||
 | 
					    CLIENT_ASSERTION,
 | 
				
			||||||
 | 
					    CLIENT_ASSERTION_TYPE,
 | 
				
			||||||
 | 
					    CLIENT_ASSERTION_TYPE_JWT,
 | 
				
			||||||
    GRANT_TYPE_AUTHORIZATION_CODE,
 | 
					    GRANT_TYPE_AUTHORIZATION_CODE,
 | 
				
			||||||
    GRANT_TYPE_CLIENT_CREDENTIALS,
 | 
					    GRANT_TYPE_CLIENT_CREDENTIALS,
 | 
				
			||||||
    GRANT_TYPE_REFRESH_TOKEN,
 | 
					    GRANT_TYPE_REFRESH_TOKEN,
 | 
				
			||||||
@ -21,6 +34,7 @@ from authentik.providers.oauth2.errors import TokenError, UserAuthError
 | 
				
			|||||||
from authentik.providers.oauth2.models import (
 | 
					from authentik.providers.oauth2.models import (
 | 
				
			||||||
    AuthorizationCode,
 | 
					    AuthorizationCode,
 | 
				
			||||||
    ClientTypes,
 | 
					    ClientTypes,
 | 
				
			||||||
 | 
					    JWTAlgorithms,
 | 
				
			||||||
    OAuth2Provider,
 | 
					    OAuth2Provider,
 | 
				
			||||||
    RefreshToken,
 | 
					    RefreshToken,
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
@ -187,6 +201,8 @@ class TokenParams:
 | 
				
			|||||||
            raise TokenError("invalid_grant")
 | 
					            raise TokenError("invalid_grant")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def __post_init_client_credentials(self, request: HttpRequest):
 | 
					    def __post_init_client_credentials(self, request: HttpRequest):
 | 
				
			||||||
 | 
					        if request.POST.get(CLIENT_ASSERTION_TYPE, "") != "":
 | 
				
			||||||
 | 
					            return self.__post_init_client_credentials_jwt(request)
 | 
				
			||||||
        # Authenticate user based on credentials
 | 
					        # Authenticate user based on credentials
 | 
				
			||||||
        username = request.POST.get("username")
 | 
					        username = request.POST.get("username")
 | 
				
			||||||
        password = request.POST.get("password")
 | 
					        password = request.POST.get("password")
 | 
				
			||||||
@ -222,6 +238,72 @@ class TokenParams:
 | 
				
			|||||||
        if not result.passing:
 | 
					        if not result.passing:
 | 
				
			||||||
            LOGGER.info("User not authenticated for application", user=self.user, app=app)
 | 
					            LOGGER.info("User not authenticated for application", user=self.user, app=app)
 | 
				
			||||||
            raise TokenError("invalid_grant")
 | 
					            raise TokenError("invalid_grant")
 | 
				
			||||||
 | 
					        return None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def __post_init_client_credentials_jwt(self, request: HttpRequest):
 | 
				
			||||||
 | 
					        assertion_type = request.POST.get(CLIENT_ASSERTION_TYPE, "")
 | 
				
			||||||
 | 
					        if assertion_type != CLIENT_ASSERTION_TYPE_JWT:
 | 
				
			||||||
 | 
					            raise TokenError("invalid_grant")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        client_secret = request.POST.get("client_secret", None)
 | 
				
			||||||
 | 
					        assertion = request.POST.get(CLIENT_ASSERTION, client_secret)
 | 
				
			||||||
 | 
					        if not assertion:
 | 
				
			||||||
 | 
					            raise TokenError("invalid_grant")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        token = None
 | 
				
			||||||
 | 
					        for cert in self.provider.verification_keys.all():
 | 
				
			||||||
 | 
					            LOGGER.debug("verifying jwt with key", key=cert.name)
 | 
				
			||||||
 | 
					            try:
 | 
				
			||||||
 | 
					                token = decode(
 | 
				
			||||||
 | 
					                    assertion,
 | 
				
			||||||
 | 
					                    cert.certificate.public_key(),
 | 
				
			||||||
 | 
					                    algorithms=[JWTAlgorithms.RS256, JWTAlgorithms.EC256],
 | 
				
			||||||
 | 
					                    options={
 | 
				
			||||||
 | 
					                        "verify_aud": False,
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                )
 | 
				
			||||||
 | 
					            except (InvalidTokenError, ValueError) as last_exc:
 | 
				
			||||||
 | 
					                LOGGER.warning("failed to validate jwt", last_exc=last_exc)
 | 
				
			||||||
 | 
					        if not token:
 | 
				
			||||||
 | 
					            raise TokenError("invalid_grant")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        exp = datetime.fromtimestamp(token["exp"])
 | 
				
			||||||
 | 
					        # Non-timezone aware check since we assume `exp` is in UTC
 | 
				
			||||||
 | 
					        if datetime.now() >= exp:
 | 
				
			||||||
 | 
					            LOGGER.info("JWT token expired")
 | 
				
			||||||
 | 
					            raise TokenError("invalid_grant")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        app = Application.objects.filter(provider=self.provider).first()
 | 
				
			||||||
 | 
					        if not app or not app.provider:
 | 
				
			||||||
 | 
					            LOGGER.info("client_credentials grant for provider without application")
 | 
				
			||||||
 | 
					            raise TokenError("invalid_grant")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        engine = PolicyEngine(app, self.user, request)
 | 
				
			||||||
 | 
					        engine.request.context["JWT"] = token
 | 
				
			||||||
 | 
					        engine.build()
 | 
				
			||||||
 | 
					        result = engine.result
 | 
				
			||||||
 | 
					        if not result.passing:
 | 
				
			||||||
 | 
					            LOGGER.info("JWT not authenticated for application", app=app)
 | 
				
			||||||
 | 
					            raise TokenError("invalid_grant")
 | 
				
			||||||
 | 
					        self.user, _ = User.objects.update_or_create(
 | 
				
			||||||
 | 
					            username=f"{self.provider.name}-{token.get('sub')}",
 | 
				
			||||||
 | 
					            defaults={
 | 
				
			||||||
 | 
					                "attributes": {
 | 
				
			||||||
 | 
					                    USER_ATTRIBUTE_GENERATED: True,
 | 
				
			||||||
 | 
					                    USER_ATTRIBUTE_EXPIRES: token["exp"],
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					                "last_login": now(),
 | 
				
			||||||
 | 
					                "name": f"Autogenerated user from application {app.name} (client credentials JWT)",
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Event.new(
 | 
				
			||||||
 | 
					            action=EventAction.LOGIN,
 | 
				
			||||||
 | 
					            PLAN_CONTEXT_METHOD="jwt",
 | 
				
			||||||
 | 
					            PLAN_CONTEXT_METHOD_ARGS={
 | 
				
			||||||
 | 
					                "jwt": token,
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					        ).from_http(request, user=self.user)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class TokenView(View):
 | 
					class TokenView(View):
 | 
				
			||||||
 | 
				
			|||||||
@ -345,6 +345,11 @@ CELERY_BEAT_SCHEDULE = {
 | 
				
			|||||||
        "schedule": crontab(hour="*/24", minute=0),
 | 
					        "schedule": crontab(hour="*/24", minute=0),
 | 
				
			||||||
        "options": {"queue": "authentik_scheduled"},
 | 
					        "options": {"queue": "authentik_scheduled"},
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					    "user_cleanup": {
 | 
				
			||||||
 | 
					        "task": "authentik.core.tasks.clean_temporary_users",
 | 
				
			||||||
 | 
					        "schedule": crontab(minute="*/5"),
 | 
				
			||||||
 | 
					        "options": {"queue": "authentik_scheduled"},
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
CELERY_TASK_CREATE_MISSING_QUEUES = True
 | 
					CELERY_TASK_CREATE_MISSING_QUEUES = True
 | 
				
			||||||
CELERY_TASK_DEFAULT_QUEUE = "authentik"
 | 
					CELERY_TASK_DEFAULT_QUEUE = "authentik"
 | 
				
			||||||
 | 
				
			|||||||
@ -6,7 +6,7 @@ from django.apps import AppConfig
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class AuthentikSourceSAMLConfig(AppConfig):
 | 
					class AuthentikSourceSAMLConfig(AppConfig):
 | 
				
			||||||
    """authentik saml_idp app config"""
 | 
					    """authentik saml source app config"""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    name = "authentik.sources.saml"
 | 
					    name = "authentik.sources.saml"
 | 
				
			||||||
    label = "authentik_sources_saml"
 | 
					    label = "authentik_sources_saml"
 | 
				
			||||||
 | 
				
			|||||||
@ -1,5 +1,6 @@
 | 
				
			|||||||
"""authentik saml source processor"""
 | 
					"""authentik saml source processor"""
 | 
				
			||||||
from base64 import b64decode
 | 
					from base64 import b64decode
 | 
				
			||||||
 | 
					from time import mktime
 | 
				
			||||||
from typing import TYPE_CHECKING, Any
 | 
					from typing import TYPE_CHECKING, Any
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import xmlsec
 | 
					import xmlsec
 | 
				
			||||||
@ -7,9 +8,16 @@ from defusedxml.lxml import fromstring
 | 
				
			|||||||
from django.core.cache import cache
 | 
					from django.core.cache import cache
 | 
				
			||||||
from django.core.exceptions import SuspiciousOperation
 | 
					from django.core.exceptions import SuspiciousOperation
 | 
				
			||||||
from django.http import HttpRequest, HttpResponse
 | 
					from django.http import HttpRequest, HttpResponse
 | 
				
			||||||
 | 
					from django.utils.timezone import now
 | 
				
			||||||
from structlog.stdlib import get_logger
 | 
					from structlog.stdlib import get_logger
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from authentik.core.models import User
 | 
					from authentik.core.models import (
 | 
				
			||||||
 | 
					    USER_ATTRIBUTE_DELETE_ON_LOGOUT,
 | 
				
			||||||
 | 
					    USER_ATTRIBUTE_EXPIRES,
 | 
				
			||||||
 | 
					    USER_ATTRIBUTE_GENERATED,
 | 
				
			||||||
 | 
					    USER_ATTRIBUTE_SOURCES,
 | 
				
			||||||
 | 
					    User,
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
from authentik.flows.models import Flow
 | 
					from authentik.flows.models import Flow
 | 
				
			||||||
from authentik.flows.planner import (
 | 
					from authentik.flows.planner import (
 | 
				
			||||||
    PLAN_CONTEXT_PENDING_USER,
 | 
					    PLAN_CONTEXT_PENDING_USER,
 | 
				
			||||||
@ -19,6 +27,7 @@ from authentik.flows.planner import (
 | 
				
			|||||||
    FlowPlanner,
 | 
					    FlowPlanner,
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
from authentik.flows.views.executor import NEXT_ARG_NAME, SESSION_KEY_GET, SESSION_KEY_PLAN
 | 
					from authentik.flows.views.executor import NEXT_ARG_NAME, SESSION_KEY_GET, SESSION_KEY_PLAN
 | 
				
			||||||
 | 
					from authentik.lib.utils.time import timedelta_from_string
 | 
				
			||||||
from authentik.lib.utils.urls import redirect_with_qs
 | 
					from authentik.lib.utils.urls import redirect_with_qs
 | 
				
			||||||
from authentik.policies.utils import delete_none_keys
 | 
					from authentik.policies.utils import delete_none_keys
 | 
				
			||||||
from authentik.sources.saml.exceptions import (
 | 
					from authentik.sources.saml.exceptions import (
 | 
				
			||||||
@ -124,9 +133,19 @@ class ResponseProcessor:
 | 
				
			|||||||
        on logout and periodically."""
 | 
					        on logout and periodically."""
 | 
				
			||||||
        # Create a temporary User
 | 
					        # Create a temporary User
 | 
				
			||||||
        name_id = self._get_name_id().text
 | 
					        name_id = self._get_name_id().text
 | 
				
			||||||
 | 
					        expiry = mktime(
 | 
				
			||||||
 | 
					            (now() + timedelta_from_string(self._source.temporary_user_delete_after)).timetuple()
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
        user: User = User.objects.create(
 | 
					        user: User = User.objects.create(
 | 
				
			||||||
            username=name_id,
 | 
					            username=name_id,
 | 
				
			||||||
            attributes={"saml": {"source": self._source.pk.hex, "delete_on_logout": True}},
 | 
					            attributes={
 | 
				
			||||||
 | 
					                USER_ATTRIBUTE_GENERATED: True,
 | 
				
			||||||
 | 
					                USER_ATTRIBUTE_SOURCES: [
 | 
				
			||||||
 | 
					                    self._source.name,
 | 
				
			||||||
 | 
					                ],
 | 
				
			||||||
 | 
					                USER_ATTRIBUTE_DELETE_ON_LOGOUT: True,
 | 
				
			||||||
 | 
					                USER_ATTRIBUTE_EXPIRES: expiry,
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
        LOGGER.debug("Created temporary user for NameID Transient", username=name_id)
 | 
					        LOGGER.debug("Created temporary user for NameID Transient", username=name_id)
 | 
				
			||||||
        user.set_unusable_password()
 | 
					        user.set_unusable_password()
 | 
				
			||||||
 | 
				
			|||||||
@ -1,10 +0,0 @@
 | 
				
			|||||||
"""saml source settings"""
 | 
					 | 
				
			||||||
from celery.schedules import crontab
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
CELERY_BEAT_SCHEDULE = {
 | 
					 | 
				
			||||||
    "saml_source_cleanup": {
 | 
					 | 
				
			||||||
        "task": "authentik.sources.saml.tasks.clean_temporary_users",
 | 
					 | 
				
			||||||
        "schedule": crontab(minute="*/5"),
 | 
					 | 
				
			||||||
        "options": {"queue": "authentik_scheduled"},
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@ -4,7 +4,7 @@ from django.dispatch import receiver
 | 
				
			|||||||
from django.http import HttpRequest
 | 
					from django.http import HttpRequest
 | 
				
			||||||
from structlog.stdlib import get_logger
 | 
					from structlog.stdlib import get_logger
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from authentik.core.models import User
 | 
					from authentik.core.models import USER_ATTRIBUTE_DELETE_ON_LOGOUT, User
 | 
				
			||||||
 | 
					
 | 
				
			||||||
LOGGER = get_logger()
 | 
					LOGGER = get_logger()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -15,8 +15,6 @@ def on_user_logged_out(sender, request: HttpRequest, user: User, **_):
 | 
				
			|||||||
    """Delete temporary user if the `delete_on_logout` flag is enabled"""
 | 
					    """Delete temporary user if the `delete_on_logout` flag is enabled"""
 | 
				
			||||||
    if not user:
 | 
					    if not user:
 | 
				
			||||||
        return
 | 
					        return
 | 
				
			||||||
    if "saml" in user.attributes:
 | 
					    if user.attributes.get(USER_ATTRIBUTE_DELETE_ON_LOGOUT, False):
 | 
				
			||||||
        if "delete_on_logout" in user.attributes["saml"]:
 | 
					        LOGGER.debug("Deleted temporary user", user=user)
 | 
				
			||||||
            if user.attributes["saml"]["delete_on_logout"]:
 | 
					        user.delete()
 | 
				
			||||||
                LOGGER.debug("Deleted temporary user", user=user)
 | 
					 | 
				
			||||||
                user.delete()
 | 
					 | 
				
			||||||
 | 
				
			|||||||
@ -1,42 +0,0 @@
 | 
				
			|||||||
"""authentik saml source tasks"""
 | 
					 | 
				
			||||||
from django.utils.timezone import now
 | 
					 | 
				
			||||||
from structlog.stdlib import get_logger
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
from authentik.core.models import AuthenticatedSession, User
 | 
					 | 
				
			||||||
from authentik.events.monitored_tasks import (
 | 
					 | 
				
			||||||
    MonitoredTask,
 | 
					 | 
				
			||||||
    TaskResult,
 | 
					 | 
				
			||||||
    TaskResultStatus,
 | 
					 | 
				
			||||||
    prefill_task,
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
from authentik.lib.utils.time import timedelta_from_string
 | 
					 | 
				
			||||||
from authentik.root.celery import CELERY_APP
 | 
					 | 
				
			||||||
from authentik.sources.saml.models import SAMLSource
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
LOGGER = get_logger()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
@CELERY_APP.task(bind=True, base=MonitoredTask)
 | 
					 | 
				
			||||||
@prefill_task
 | 
					 | 
				
			||||||
def clean_temporary_users(self: MonitoredTask):
 | 
					 | 
				
			||||||
    """Remove temporary users created by SAML Sources"""
 | 
					 | 
				
			||||||
    _now = now()
 | 
					 | 
				
			||||||
    messages = []
 | 
					 | 
				
			||||||
    deleted_users = 0
 | 
					 | 
				
			||||||
    for user in User.objects.filter(attributes__saml__isnull=False):
 | 
					 | 
				
			||||||
        sources = SAMLSource.objects.filter(pk=user.attributes.get("saml", {}).get("source", ""))
 | 
					 | 
				
			||||||
        if not sources.exists():
 | 
					 | 
				
			||||||
            LOGGER.warning("User has an invalid SAML Source and won't be deleted!", user=user)
 | 
					 | 
				
			||||||
            messages.append(f"User {user} has an invalid SAML Source and won't be deleted!")
 | 
					 | 
				
			||||||
            continue
 | 
					 | 
				
			||||||
        source = sources.first()
 | 
					 | 
				
			||||||
        source_delta = timedelta_from_string(source.temporary_user_delete_after)
 | 
					 | 
				
			||||||
        if (
 | 
					 | 
				
			||||||
            _now - user.last_login >= source_delta
 | 
					 | 
				
			||||||
            and not AuthenticatedSession.objects.filter(user=user).exists()
 | 
					 | 
				
			||||||
        ):
 | 
					 | 
				
			||||||
            LOGGER.debug("User is expired and will be deleted.", user=user, delta=source_delta)
 | 
					 | 
				
			||||||
            user.delete()
 | 
					 | 
				
			||||||
            deleted_users += 1
 | 
					 | 
				
			||||||
    messages.append(f"Successfully deleted {deleted_users} users.")
 | 
					 | 
				
			||||||
    self.set_status(TaskResult(TaskResultStatus.SUCCESSFUL, messages))
 | 
					 | 
				
			||||||
							
								
								
									
										32
									
								
								schema.yml
									
									
									
									
									
								
							
							
						
						
									
										32
									
								
								schema.yml
									
									
									
									
									
								
							@ -23091,7 +23091,6 @@ components:
 | 
				
			|||||||
          type: string
 | 
					          type: string
 | 
				
			||||||
          format: uuid
 | 
					          format: uuid
 | 
				
			||||||
          nullable: true
 | 
					          nullable: true
 | 
				
			||||||
          title: RSA Key
 | 
					 | 
				
			||||||
          description: Key used to sign the tokens. Only required when JWT Algorithm
 | 
					          description: Key used to sign the tokens. Only required when JWT Algorithm
 | 
				
			||||||
            is set to RS256.
 | 
					            is set to RS256.
 | 
				
			||||||
        redirect_uris:
 | 
					        redirect_uris:
 | 
				
			||||||
@ -23106,6 +23105,15 @@ components:
 | 
				
			|||||||
          allOf:
 | 
					          allOf:
 | 
				
			||||||
          - $ref: '#/components/schemas/IssuerModeEnum'
 | 
					          - $ref: '#/components/schemas/IssuerModeEnum'
 | 
				
			||||||
          description: Configure how the issuer field of the ID Token should be filled.
 | 
					          description: Configure how the issuer field of the ID Token should be filled.
 | 
				
			||||||
 | 
					        verification_keys:
 | 
				
			||||||
 | 
					          type: array
 | 
				
			||||||
 | 
					          items:
 | 
				
			||||||
 | 
					            type: string
 | 
				
			||||||
 | 
					            format: uuid
 | 
				
			||||||
 | 
					            title: Allowed certificates for JWT-based client_credentials
 | 
				
			||||||
 | 
					          title: Allowed certificates for JWT-based client_credentials
 | 
				
			||||||
 | 
					          description: JWTs created with the configured certificates can authenticate
 | 
				
			||||||
 | 
					            with this provider.
 | 
				
			||||||
      required:
 | 
					      required:
 | 
				
			||||||
      - assigned_application_name
 | 
					      - assigned_application_name
 | 
				
			||||||
      - assigned_application_slug
 | 
					      - assigned_application_slug
 | 
				
			||||||
@ -23116,6 +23124,7 @@ components:
 | 
				
			|||||||
      - pk
 | 
					      - pk
 | 
				
			||||||
      - verbose_name
 | 
					      - verbose_name
 | 
				
			||||||
      - verbose_name_plural
 | 
					      - verbose_name_plural
 | 
				
			||||||
 | 
					      - verification_keys
 | 
				
			||||||
    OAuth2ProviderRequest:
 | 
					    OAuth2ProviderRequest:
 | 
				
			||||||
      type: object
 | 
					      type: object
 | 
				
			||||||
      description: OAuth2Provider Serializer
 | 
					      description: OAuth2Provider Serializer
 | 
				
			||||||
@ -23163,7 +23172,6 @@ components:
 | 
				
			|||||||
          type: string
 | 
					          type: string
 | 
				
			||||||
          format: uuid
 | 
					          format: uuid
 | 
				
			||||||
          nullable: true
 | 
					          nullable: true
 | 
				
			||||||
          title: RSA Key
 | 
					 | 
				
			||||||
          description: Key used to sign the tokens. Only required when JWT Algorithm
 | 
					          description: Key used to sign the tokens. Only required when JWT Algorithm
 | 
				
			||||||
            is set to RS256.
 | 
					            is set to RS256.
 | 
				
			||||||
        redirect_uris:
 | 
					        redirect_uris:
 | 
				
			||||||
@ -23178,9 +23186,19 @@ components:
 | 
				
			|||||||
          allOf:
 | 
					          allOf:
 | 
				
			||||||
          - $ref: '#/components/schemas/IssuerModeEnum'
 | 
					          - $ref: '#/components/schemas/IssuerModeEnum'
 | 
				
			||||||
          description: Configure how the issuer field of the ID Token should be filled.
 | 
					          description: Configure how the issuer field of the ID Token should be filled.
 | 
				
			||||||
 | 
					        verification_keys:
 | 
				
			||||||
 | 
					          type: array
 | 
				
			||||||
 | 
					          items:
 | 
				
			||||||
 | 
					            type: string
 | 
				
			||||||
 | 
					            format: uuid
 | 
				
			||||||
 | 
					            title: Allowed certificates for JWT-based client_credentials
 | 
				
			||||||
 | 
					          title: Allowed certificates for JWT-based client_credentials
 | 
				
			||||||
 | 
					          description: JWTs created with the configured certificates can authenticate
 | 
				
			||||||
 | 
					            with this provider.
 | 
				
			||||||
      required:
 | 
					      required:
 | 
				
			||||||
      - authorization_flow
 | 
					      - authorization_flow
 | 
				
			||||||
      - name
 | 
					      - name
 | 
				
			||||||
 | 
					      - verification_keys
 | 
				
			||||||
    OAuth2ProviderSetupURLs:
 | 
					    OAuth2ProviderSetupURLs:
 | 
				
			||||||
      type: object
 | 
					      type: object
 | 
				
			||||||
      description: OAuth2 Provider Metadata serializer
 | 
					      description: OAuth2 Provider Metadata serializer
 | 
				
			||||||
@ -27488,7 +27506,6 @@ components:
 | 
				
			|||||||
          type: string
 | 
					          type: string
 | 
				
			||||||
          format: uuid
 | 
					          format: uuid
 | 
				
			||||||
          nullable: true
 | 
					          nullable: true
 | 
				
			||||||
          title: RSA Key
 | 
					 | 
				
			||||||
          description: Key used to sign the tokens. Only required when JWT Algorithm
 | 
					          description: Key used to sign the tokens. Only required when JWT Algorithm
 | 
				
			||||||
            is set to RS256.
 | 
					            is set to RS256.
 | 
				
			||||||
        redirect_uris:
 | 
					        redirect_uris:
 | 
				
			||||||
@ -27503,6 +27520,15 @@ components:
 | 
				
			|||||||
          allOf:
 | 
					          allOf:
 | 
				
			||||||
          - $ref: '#/components/schemas/IssuerModeEnum'
 | 
					          - $ref: '#/components/schemas/IssuerModeEnum'
 | 
				
			||||||
          description: Configure how the issuer field of the ID Token should be filled.
 | 
					          description: Configure how the issuer field of the ID Token should be filled.
 | 
				
			||||||
 | 
					        verification_keys:
 | 
				
			||||||
 | 
					          type: array
 | 
				
			||||||
 | 
					          items:
 | 
				
			||||||
 | 
					            type: string
 | 
				
			||||||
 | 
					            format: uuid
 | 
				
			||||||
 | 
					            title: Allowed certificates for JWT-based client_credentials
 | 
				
			||||||
 | 
					          title: Allowed certificates for JWT-based client_credentials
 | 
				
			||||||
 | 
					          description: JWTs created with the configured certificates can authenticate
 | 
				
			||||||
 | 
					            with this provider.
 | 
				
			||||||
    PatchedOAuthSourceRequest:
 | 
					    PatchedOAuthSourceRequest:
 | 
				
			||||||
      type: object
 | 
					      type: object
 | 
				
			||||||
      description: OAuth Source Serializer
 | 
					      description: OAuth Source Serializer
 | 
				
			||||||
 | 
				
			|||||||
@ -2327,6 +2327,7 @@ msgstr "Interne Konten ausblenden"
 | 
				
			|||||||
#: src/pages/events/RuleForm.ts
 | 
					#: src/pages/events/RuleForm.ts
 | 
				
			||||||
#: src/pages/outposts/OutpostForm.ts
 | 
					#: src/pages/outposts/OutpostForm.ts
 | 
				
			||||||
#: src/pages/providers/oauth2/OAuth2ProviderForm.ts
 | 
					#: src/pages/providers/oauth2/OAuth2ProviderForm.ts
 | 
				
			||||||
 | 
					#: src/pages/providers/oauth2/OAuth2ProviderForm.ts
 | 
				
			||||||
#: src/pages/providers/proxy/ProxyProviderForm.ts
 | 
					#: src/pages/providers/proxy/ProxyProviderForm.ts
 | 
				
			||||||
#: src/pages/providers/saml/SAMLProviderForm.ts
 | 
					#: src/pages/providers/saml/SAMLProviderForm.ts
 | 
				
			||||||
#: src/pages/sources/ldap/LDAPSourceForm.ts
 | 
					#: src/pages/sources/ldap/LDAPSourceForm.ts
 | 
				
			||||||
@ -2582,6 +2583,10 @@ msgstr "Ausstellermodus"
 | 
				
			|||||||
#~ msgid "JWT Algorithm"
 | 
					#~ msgid "JWT Algorithm"
 | 
				
			||||||
#~ msgstr "JWT Algorithmus"
 | 
					#~ msgstr "JWT Algorithmus"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: src/pages/providers/oauth2/OAuth2ProviderForm.ts
 | 
				
			||||||
 | 
					msgid "JWTs signed by certificates configured here can be used to authenticate to the provider."
 | 
				
			||||||
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: src/pages/providers/oauth2/OAuth2ProviderForm.ts
 | 
					#: src/pages/providers/oauth2/OAuth2ProviderForm.ts
 | 
				
			||||||
msgid "Key used to sign the tokens."
 | 
					msgid "Key used to sign the tokens."
 | 
				
			||||||
msgstr "Schlüssel zum Signieren der Token."
 | 
					msgstr "Schlüssel zum Signieren der Token."
 | 
				
			||||||
@ -2745,6 +2750,7 @@ msgstr "Wird geladen"
 | 
				
			|||||||
#: src/pages/providers/oauth2/OAuth2ProviderForm.ts
 | 
					#: src/pages/providers/oauth2/OAuth2ProviderForm.ts
 | 
				
			||||||
#: src/pages/providers/oauth2/OAuth2ProviderForm.ts
 | 
					#: src/pages/providers/oauth2/OAuth2ProviderForm.ts
 | 
				
			||||||
#: src/pages/providers/oauth2/OAuth2ProviderForm.ts
 | 
					#: src/pages/providers/oauth2/OAuth2ProviderForm.ts
 | 
				
			||||||
 | 
					#: src/pages/providers/oauth2/OAuth2ProviderForm.ts
 | 
				
			||||||
#: src/pages/providers/proxy/ProxyProviderForm.ts
 | 
					#: src/pages/providers/proxy/ProxyProviderForm.ts
 | 
				
			||||||
#: src/pages/providers/proxy/ProxyProviderForm.ts
 | 
					#: src/pages/providers/proxy/ProxyProviderForm.ts
 | 
				
			||||||
#: src/pages/providers/proxy/ProxyProviderForm.ts
 | 
					#: src/pages/providers/proxy/ProxyProviderForm.ts
 | 
				
			||||||
@ -5906,6 +5912,10 @@ msgstr "Überprüfung"
 | 
				
			|||||||
msgid "Verification Certificate"
 | 
					msgid "Verification Certificate"
 | 
				
			||||||
msgstr "Zertifikat zur Überprüfung"
 | 
					msgstr "Zertifikat zur Überprüfung"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: src/pages/providers/oauth2/OAuth2ProviderForm.ts
 | 
				
			||||||
 | 
					msgid "Verification certificates"
 | 
				
			||||||
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: src/pages/stages/email/EmailStageForm.ts
 | 
					#: src/pages/stages/email/EmailStageForm.ts
 | 
				
			||||||
msgid "Verify the user's email address by sending them a one-time-link. Can also be used for recovery to verify the user's authenticity."
 | 
					msgid "Verify the user's email address by sending them a one-time-link. Can also be used for recovery to verify the user's authenticity."
 | 
				
			||||||
msgstr "Überprüfen Sie die E-Mail-Adresse des Benutzers, indem Sie ihm einen einmaligen Link senden. Kann auch für die Wiederherstellung verwendet werden, um die Authentizität des Benutzers zu überprüfen."
 | 
					msgstr "Überprüfen Sie die E-Mail-Adresse des Benutzers, indem Sie ihm einen einmaligen Link senden. Kann auch für die Wiederherstellung verwendet werden, um die Authentizität des Benutzers zu überprüfen."
 | 
				
			||||||
 | 
				
			|||||||
@ -2360,6 +2360,7 @@ msgstr "Hide service-accounts"
 | 
				
			|||||||
#: src/pages/events/RuleForm.ts
 | 
					#: src/pages/events/RuleForm.ts
 | 
				
			||||||
#: src/pages/outposts/OutpostForm.ts
 | 
					#: src/pages/outposts/OutpostForm.ts
 | 
				
			||||||
#: src/pages/providers/oauth2/OAuth2ProviderForm.ts
 | 
					#: src/pages/providers/oauth2/OAuth2ProviderForm.ts
 | 
				
			||||||
 | 
					#: src/pages/providers/oauth2/OAuth2ProviderForm.ts
 | 
				
			||||||
#: src/pages/providers/proxy/ProxyProviderForm.ts
 | 
					#: src/pages/providers/proxy/ProxyProviderForm.ts
 | 
				
			||||||
#: src/pages/providers/saml/SAMLProviderForm.ts
 | 
					#: src/pages/providers/saml/SAMLProviderForm.ts
 | 
				
			||||||
#: src/pages/sources/ldap/LDAPSourceForm.ts
 | 
					#: src/pages/sources/ldap/LDAPSourceForm.ts
 | 
				
			||||||
@ -2624,6 +2625,10 @@ msgstr "Issuer mode"
 | 
				
			|||||||
#~ msgid "JWT Algorithm"
 | 
					#~ msgid "JWT Algorithm"
 | 
				
			||||||
#~ msgstr "JWT Algorithm"
 | 
					#~ msgstr "JWT Algorithm"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: src/pages/providers/oauth2/OAuth2ProviderForm.ts
 | 
				
			||||||
 | 
					msgid "JWTs signed by certificates configured here can be used to authenticate to the provider."
 | 
				
			||||||
 | 
					msgstr "JWTs signed by certificates configured here can be used to authenticate to the provider."
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: src/pages/providers/oauth2/OAuth2ProviderForm.ts
 | 
					#: src/pages/providers/oauth2/OAuth2ProviderForm.ts
 | 
				
			||||||
msgid "Key used to sign the tokens."
 | 
					msgid "Key used to sign the tokens."
 | 
				
			||||||
msgstr "Key used to sign the tokens."
 | 
					msgstr "Key used to sign the tokens."
 | 
				
			||||||
@ -2789,6 +2794,7 @@ msgstr "Loading"
 | 
				
			|||||||
#: src/pages/providers/oauth2/OAuth2ProviderForm.ts
 | 
					#: src/pages/providers/oauth2/OAuth2ProviderForm.ts
 | 
				
			||||||
#: src/pages/providers/oauth2/OAuth2ProviderForm.ts
 | 
					#: src/pages/providers/oauth2/OAuth2ProviderForm.ts
 | 
				
			||||||
#: src/pages/providers/oauth2/OAuth2ProviderForm.ts
 | 
					#: src/pages/providers/oauth2/OAuth2ProviderForm.ts
 | 
				
			||||||
 | 
					#: src/pages/providers/oauth2/OAuth2ProviderForm.ts
 | 
				
			||||||
#: src/pages/providers/proxy/ProxyProviderForm.ts
 | 
					#: src/pages/providers/proxy/ProxyProviderForm.ts
 | 
				
			||||||
#: src/pages/providers/proxy/ProxyProviderForm.ts
 | 
					#: src/pages/providers/proxy/ProxyProviderForm.ts
 | 
				
			||||||
#: src/pages/providers/proxy/ProxyProviderForm.ts
 | 
					#: src/pages/providers/proxy/ProxyProviderForm.ts
 | 
				
			||||||
@ -6022,6 +6028,10 @@ msgstr "Verification"
 | 
				
			|||||||
msgid "Verification Certificate"
 | 
					msgid "Verification Certificate"
 | 
				
			||||||
msgstr "Verification Certificate"
 | 
					msgstr "Verification Certificate"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: src/pages/providers/oauth2/OAuth2ProviderForm.ts
 | 
				
			||||||
 | 
					msgid "Verification certificates"
 | 
				
			||||||
 | 
					msgstr "Verification certificates"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: src/pages/stages/email/EmailStageForm.ts
 | 
					#: src/pages/stages/email/EmailStageForm.ts
 | 
				
			||||||
msgid "Verify the user's email address by sending them a one-time-link. Can also be used for recovery to verify the user's authenticity."
 | 
					msgid "Verify the user's email address by sending them a one-time-link. Can also be used for recovery to verify the user's authenticity."
 | 
				
			||||||
msgstr "Verify the user's email address by sending them a one-time-link. Can also be used for recovery to verify the user's authenticity."
 | 
					msgstr "Verify the user's email address by sending them a one-time-link. Can also be used for recovery to verify the user's authenticity."
 | 
				
			||||||
 | 
				
			|||||||
@ -2318,6 +2318,7 @@ msgstr "Ocultar cuentas de servicio"
 | 
				
			|||||||
#: src/pages/events/RuleForm.ts
 | 
					#: src/pages/events/RuleForm.ts
 | 
				
			||||||
#: src/pages/outposts/OutpostForm.ts
 | 
					#: src/pages/outposts/OutpostForm.ts
 | 
				
			||||||
#: src/pages/providers/oauth2/OAuth2ProviderForm.ts
 | 
					#: src/pages/providers/oauth2/OAuth2ProviderForm.ts
 | 
				
			||||||
 | 
					#: src/pages/providers/oauth2/OAuth2ProviderForm.ts
 | 
				
			||||||
#: src/pages/providers/proxy/ProxyProviderForm.ts
 | 
					#: src/pages/providers/proxy/ProxyProviderForm.ts
 | 
				
			||||||
#: src/pages/providers/saml/SAMLProviderForm.ts
 | 
					#: src/pages/providers/saml/SAMLProviderForm.ts
 | 
				
			||||||
#: src/pages/sources/ldap/LDAPSourceForm.ts
 | 
					#: src/pages/sources/ldap/LDAPSourceForm.ts
 | 
				
			||||||
@ -2575,6 +2576,10 @@ msgstr "Modo emisor"
 | 
				
			|||||||
#~ msgid "JWT Algorithm"
 | 
					#~ msgid "JWT Algorithm"
 | 
				
			||||||
#~ msgstr "algoritmo JWT"
 | 
					#~ msgstr "algoritmo JWT"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: src/pages/providers/oauth2/OAuth2ProviderForm.ts
 | 
				
			||||||
 | 
					msgid "JWTs signed by certificates configured here can be used to authenticate to the provider."
 | 
				
			||||||
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: src/pages/providers/oauth2/OAuth2ProviderForm.ts
 | 
					#: src/pages/providers/oauth2/OAuth2ProviderForm.ts
 | 
				
			||||||
msgid "Key used to sign the tokens."
 | 
					msgid "Key used to sign the tokens."
 | 
				
			||||||
msgstr "Clave utilizada para firmar los tokens."
 | 
					msgstr "Clave utilizada para firmar los tokens."
 | 
				
			||||||
@ -2738,6 +2743,7 @@ msgstr "Cargando"
 | 
				
			|||||||
#: src/pages/providers/oauth2/OAuth2ProviderForm.ts
 | 
					#: src/pages/providers/oauth2/OAuth2ProviderForm.ts
 | 
				
			||||||
#: src/pages/providers/oauth2/OAuth2ProviderForm.ts
 | 
					#: src/pages/providers/oauth2/OAuth2ProviderForm.ts
 | 
				
			||||||
#: src/pages/providers/oauth2/OAuth2ProviderForm.ts
 | 
					#: src/pages/providers/oauth2/OAuth2ProviderForm.ts
 | 
				
			||||||
 | 
					#: src/pages/providers/oauth2/OAuth2ProviderForm.ts
 | 
				
			||||||
#: src/pages/providers/proxy/ProxyProviderForm.ts
 | 
					#: src/pages/providers/proxy/ProxyProviderForm.ts
 | 
				
			||||||
#: src/pages/providers/proxy/ProxyProviderForm.ts
 | 
					#: src/pages/providers/proxy/ProxyProviderForm.ts
 | 
				
			||||||
#: src/pages/providers/proxy/ProxyProviderForm.ts
 | 
					#: src/pages/providers/proxy/ProxyProviderForm.ts
 | 
				
			||||||
@ -5900,6 +5906,10 @@ msgstr "Verificación"
 | 
				
			|||||||
msgid "Verification Certificate"
 | 
					msgid "Verification Certificate"
 | 
				
			||||||
msgstr "Certificado de verificación"
 | 
					msgstr "Certificado de verificación"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: src/pages/providers/oauth2/OAuth2ProviderForm.ts
 | 
				
			||||||
 | 
					msgid "Verification certificates"
 | 
				
			||||||
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: src/pages/stages/email/EmailStageForm.ts
 | 
					#: src/pages/stages/email/EmailStageForm.ts
 | 
				
			||||||
msgid "Verify the user's email address by sending them a one-time-link. Can also be used for recovery to verify the user's authenticity."
 | 
					msgid "Verify the user's email address by sending them a one-time-link. Can also be used for recovery to verify the user's authenticity."
 | 
				
			||||||
msgstr "Verifique la dirección de correo electrónico del usuario enviándole un enlace único. También se puede utilizar para la recuperación para verificar la autenticidad del usuario."
 | 
					msgstr "Verifique la dirección de correo electrónico del usuario enviándole un enlace único. También se puede utilizar para la recuperación para verificar la autenticidad del usuario."
 | 
				
			||||||
 | 
				
			|||||||
@ -2344,6 +2344,7 @@ msgstr "Cacher les comptes de service"
 | 
				
			|||||||
#: src/pages/events/RuleForm.ts
 | 
					#: src/pages/events/RuleForm.ts
 | 
				
			||||||
#: src/pages/outposts/OutpostForm.ts
 | 
					#: src/pages/outposts/OutpostForm.ts
 | 
				
			||||||
#: src/pages/providers/oauth2/OAuth2ProviderForm.ts
 | 
					#: src/pages/providers/oauth2/OAuth2ProviderForm.ts
 | 
				
			||||||
 | 
					#: src/pages/providers/oauth2/OAuth2ProviderForm.ts
 | 
				
			||||||
#: src/pages/providers/proxy/ProxyProviderForm.ts
 | 
					#: src/pages/providers/proxy/ProxyProviderForm.ts
 | 
				
			||||||
#: src/pages/providers/saml/SAMLProviderForm.ts
 | 
					#: src/pages/providers/saml/SAMLProviderForm.ts
 | 
				
			||||||
#: src/pages/sources/ldap/LDAPSourceForm.ts
 | 
					#: src/pages/sources/ldap/LDAPSourceForm.ts
 | 
				
			||||||
@ -2605,6 +2606,10 @@ msgstr "Mode de l'émetteur"
 | 
				
			|||||||
#~ msgid "JWT Algorithm"
 | 
					#~ msgid "JWT Algorithm"
 | 
				
			||||||
#~ msgstr "Algorithme JWT"
 | 
					#~ msgstr "Algorithme JWT"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: src/pages/providers/oauth2/OAuth2ProviderForm.ts
 | 
				
			||||||
 | 
					msgid "JWTs signed by certificates configured here can be used to authenticate to the provider."
 | 
				
			||||||
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: src/pages/providers/oauth2/OAuth2ProviderForm.ts
 | 
					#: src/pages/providers/oauth2/OAuth2ProviderForm.ts
 | 
				
			||||||
msgid "Key used to sign the tokens."
 | 
					msgid "Key used to sign the tokens."
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
@ -2769,6 +2774,7 @@ msgstr "Chargement en cours"
 | 
				
			|||||||
#: src/pages/providers/oauth2/OAuth2ProviderForm.ts
 | 
					#: src/pages/providers/oauth2/OAuth2ProviderForm.ts
 | 
				
			||||||
#: src/pages/providers/oauth2/OAuth2ProviderForm.ts
 | 
					#: src/pages/providers/oauth2/OAuth2ProviderForm.ts
 | 
				
			||||||
#: src/pages/providers/oauth2/OAuth2ProviderForm.ts
 | 
					#: src/pages/providers/oauth2/OAuth2ProviderForm.ts
 | 
				
			||||||
 | 
					#: src/pages/providers/oauth2/OAuth2ProviderForm.ts
 | 
				
			||||||
#: src/pages/providers/proxy/ProxyProviderForm.ts
 | 
					#: src/pages/providers/proxy/ProxyProviderForm.ts
 | 
				
			||||||
#: src/pages/providers/proxy/ProxyProviderForm.ts
 | 
					#: src/pages/providers/proxy/ProxyProviderForm.ts
 | 
				
			||||||
#: src/pages/providers/proxy/ProxyProviderForm.ts
 | 
					#: src/pages/providers/proxy/ProxyProviderForm.ts
 | 
				
			||||||
@ -5961,6 +5967,10 @@ msgstr "Vérification"
 | 
				
			|||||||
msgid "Verification Certificate"
 | 
					msgid "Verification Certificate"
 | 
				
			||||||
msgstr "Certificat de validation"
 | 
					msgstr "Certificat de validation"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: src/pages/providers/oauth2/OAuth2ProviderForm.ts
 | 
				
			||||||
 | 
					msgid "Verification certificates"
 | 
				
			||||||
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: src/pages/stages/email/EmailStageForm.ts
 | 
					#: src/pages/stages/email/EmailStageForm.ts
 | 
				
			||||||
msgid "Verify the user's email address by sending them a one-time-link. Can also be used for recovery to verify the user's authenticity."
 | 
					msgid "Verify the user's email address by sending them a one-time-link. Can also be used for recovery to verify the user's authenticity."
 | 
				
			||||||
msgstr "Vérifier le courriel de l'utilisateur en lui envoyant un lien à usage unique. Peut également être utilisé lors de la récupération afin de vérifier l'authenticité de l'utilisateur."
 | 
					msgstr "Vérifier le courriel de l'utilisateur en lui envoyant un lien à usage unique. Peut également être utilisé lors de la récupération afin de vérifier l'authenticité de l'utilisateur."
 | 
				
			||||||
 | 
				
			|||||||
@ -2315,6 +2315,7 @@ msgstr "Ukryj konta serwisowe"
 | 
				
			|||||||
#: src/pages/events/RuleForm.ts
 | 
					#: src/pages/events/RuleForm.ts
 | 
				
			||||||
#: src/pages/outposts/OutpostForm.ts
 | 
					#: src/pages/outposts/OutpostForm.ts
 | 
				
			||||||
#: src/pages/providers/oauth2/OAuth2ProviderForm.ts
 | 
					#: src/pages/providers/oauth2/OAuth2ProviderForm.ts
 | 
				
			||||||
 | 
					#: src/pages/providers/oauth2/OAuth2ProviderForm.ts
 | 
				
			||||||
#: src/pages/providers/proxy/ProxyProviderForm.ts
 | 
					#: src/pages/providers/proxy/ProxyProviderForm.ts
 | 
				
			||||||
#: src/pages/providers/saml/SAMLProviderForm.ts
 | 
					#: src/pages/providers/saml/SAMLProviderForm.ts
 | 
				
			||||||
#: src/pages/sources/ldap/LDAPSourceForm.ts
 | 
					#: src/pages/sources/ldap/LDAPSourceForm.ts
 | 
				
			||||||
@ -2572,6 +2573,10 @@ msgstr "Tryb wystawcy"
 | 
				
			|||||||
#~ msgid "JWT Algorithm"
 | 
					#~ msgid "JWT Algorithm"
 | 
				
			||||||
#~ msgstr "Algorytm JWT"
 | 
					#~ msgstr "Algorytm JWT"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: src/pages/providers/oauth2/OAuth2ProviderForm.ts
 | 
				
			||||||
 | 
					msgid "JWTs signed by certificates configured here can be used to authenticate to the provider."
 | 
				
			||||||
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: src/pages/providers/oauth2/OAuth2ProviderForm.ts
 | 
					#: src/pages/providers/oauth2/OAuth2ProviderForm.ts
 | 
				
			||||||
msgid "Key used to sign the tokens."
 | 
					msgid "Key used to sign the tokens."
 | 
				
			||||||
msgstr "Klucz używany do podpisywania tokenów."
 | 
					msgstr "Klucz używany do podpisywania tokenów."
 | 
				
			||||||
@ -2735,6 +2740,7 @@ msgstr "Ładowanie"
 | 
				
			|||||||
#: src/pages/providers/oauth2/OAuth2ProviderForm.ts
 | 
					#: src/pages/providers/oauth2/OAuth2ProviderForm.ts
 | 
				
			||||||
#: src/pages/providers/oauth2/OAuth2ProviderForm.ts
 | 
					#: src/pages/providers/oauth2/OAuth2ProviderForm.ts
 | 
				
			||||||
#: src/pages/providers/oauth2/OAuth2ProviderForm.ts
 | 
					#: src/pages/providers/oauth2/OAuth2ProviderForm.ts
 | 
				
			||||||
 | 
					#: src/pages/providers/oauth2/OAuth2ProviderForm.ts
 | 
				
			||||||
#: src/pages/providers/proxy/ProxyProviderForm.ts
 | 
					#: src/pages/providers/proxy/ProxyProviderForm.ts
 | 
				
			||||||
#: src/pages/providers/proxy/ProxyProviderForm.ts
 | 
					#: src/pages/providers/proxy/ProxyProviderForm.ts
 | 
				
			||||||
#: src/pages/providers/proxy/ProxyProviderForm.ts
 | 
					#: src/pages/providers/proxy/ProxyProviderForm.ts
 | 
				
			||||||
@ -5897,6 +5903,10 @@ msgstr "Weryfikacja"
 | 
				
			|||||||
msgid "Verification Certificate"
 | 
					msgid "Verification Certificate"
 | 
				
			||||||
msgstr "Certyfikat weryfikacji"
 | 
					msgstr "Certyfikat weryfikacji"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: src/pages/providers/oauth2/OAuth2ProviderForm.ts
 | 
				
			||||||
 | 
					msgid "Verification certificates"
 | 
				
			||||||
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: src/pages/stages/email/EmailStageForm.ts
 | 
					#: src/pages/stages/email/EmailStageForm.ts
 | 
				
			||||||
msgid "Verify the user's email address by sending them a one-time-link. Can also be used for recovery to verify the user's authenticity."
 | 
					msgid "Verify the user's email address by sending them a one-time-link. Can also be used for recovery to verify the user's authenticity."
 | 
				
			||||||
msgstr "Zweryfikuj adres e-mail użytkownika, wysyłając mu jednorazowy link. Może być również używany do odzyskiwania w celu weryfikacji autentyczności użytkownika."
 | 
					msgstr "Zweryfikuj adres e-mail użytkownika, wysyłając mu jednorazowy link. Może być również używany do odzyskiwania w celu weryfikacji autentyczności użytkownika."
 | 
				
			||||||
 | 
				
			|||||||
@ -2352,6 +2352,7 @@ msgstr ""
 | 
				
			|||||||
#: src/pages/events/RuleForm.ts
 | 
					#: src/pages/events/RuleForm.ts
 | 
				
			||||||
#: src/pages/outposts/OutpostForm.ts
 | 
					#: src/pages/outposts/OutpostForm.ts
 | 
				
			||||||
#: src/pages/providers/oauth2/OAuth2ProviderForm.ts
 | 
					#: src/pages/providers/oauth2/OAuth2ProviderForm.ts
 | 
				
			||||||
 | 
					#: src/pages/providers/oauth2/OAuth2ProviderForm.ts
 | 
				
			||||||
#: src/pages/providers/proxy/ProxyProviderForm.ts
 | 
					#: src/pages/providers/proxy/ProxyProviderForm.ts
 | 
				
			||||||
#: src/pages/providers/saml/SAMLProviderForm.ts
 | 
					#: src/pages/providers/saml/SAMLProviderForm.ts
 | 
				
			||||||
#: src/pages/sources/ldap/LDAPSourceForm.ts
 | 
					#: src/pages/sources/ldap/LDAPSourceForm.ts
 | 
				
			||||||
@ -2614,6 +2615,10 @@ msgstr ""
 | 
				
			|||||||
#~ msgid "JWT Algorithm"
 | 
					#~ msgid "JWT Algorithm"
 | 
				
			||||||
#~ msgstr ""
 | 
					#~ msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: src/pages/providers/oauth2/OAuth2ProviderForm.ts
 | 
				
			||||||
 | 
					msgid "JWTs signed by certificates configured here can be used to authenticate to the provider."
 | 
				
			||||||
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: src/pages/providers/oauth2/OAuth2ProviderForm.ts
 | 
					#: src/pages/providers/oauth2/OAuth2ProviderForm.ts
 | 
				
			||||||
msgid "Key used to sign the tokens."
 | 
					msgid "Key used to sign the tokens."
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
@ -2779,6 +2784,7 @@ msgstr ""
 | 
				
			|||||||
#: src/pages/providers/oauth2/OAuth2ProviderForm.ts
 | 
					#: src/pages/providers/oauth2/OAuth2ProviderForm.ts
 | 
				
			||||||
#: src/pages/providers/oauth2/OAuth2ProviderForm.ts
 | 
					#: src/pages/providers/oauth2/OAuth2ProviderForm.ts
 | 
				
			||||||
#: src/pages/providers/oauth2/OAuth2ProviderForm.ts
 | 
					#: src/pages/providers/oauth2/OAuth2ProviderForm.ts
 | 
				
			||||||
 | 
					#: src/pages/providers/oauth2/OAuth2ProviderForm.ts
 | 
				
			||||||
#: src/pages/providers/proxy/ProxyProviderForm.ts
 | 
					#: src/pages/providers/proxy/ProxyProviderForm.ts
 | 
				
			||||||
#: src/pages/providers/proxy/ProxyProviderForm.ts
 | 
					#: src/pages/providers/proxy/ProxyProviderForm.ts
 | 
				
			||||||
#: src/pages/providers/proxy/ProxyProviderForm.ts
 | 
					#: src/pages/providers/proxy/ProxyProviderForm.ts
 | 
				
			||||||
@ -6002,6 +6008,10 @@ msgstr ""
 | 
				
			|||||||
msgid "Verification Certificate"
 | 
					msgid "Verification Certificate"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: src/pages/providers/oauth2/OAuth2ProviderForm.ts
 | 
				
			||||||
 | 
					msgid "Verification certificates"
 | 
				
			||||||
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: src/pages/stages/email/EmailStageForm.ts
 | 
					#: src/pages/stages/email/EmailStageForm.ts
 | 
				
			||||||
msgid "Verify the user's email address by sending them a one-time-link. Can also be used for recovery to verify the user's authenticity."
 | 
					msgid "Verify the user's email address by sending them a one-time-link. Can also be used for recovery to verify the user's authenticity."
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
				
			|||||||
@ -2318,6 +2318,7 @@ msgstr "Hizmet hesaplarını gizle"
 | 
				
			|||||||
#: src/pages/events/RuleForm.ts
 | 
					#: src/pages/events/RuleForm.ts
 | 
				
			||||||
#: src/pages/outposts/OutpostForm.ts
 | 
					#: src/pages/outposts/OutpostForm.ts
 | 
				
			||||||
#: src/pages/providers/oauth2/OAuth2ProviderForm.ts
 | 
					#: src/pages/providers/oauth2/OAuth2ProviderForm.ts
 | 
				
			||||||
 | 
					#: src/pages/providers/oauth2/OAuth2ProviderForm.ts
 | 
				
			||||||
#: src/pages/providers/proxy/ProxyProviderForm.ts
 | 
					#: src/pages/providers/proxy/ProxyProviderForm.ts
 | 
				
			||||||
#: src/pages/providers/saml/SAMLProviderForm.ts
 | 
					#: src/pages/providers/saml/SAMLProviderForm.ts
 | 
				
			||||||
#: src/pages/sources/ldap/LDAPSourceForm.ts
 | 
					#: src/pages/sources/ldap/LDAPSourceForm.ts
 | 
				
			||||||
@ -2576,6 +2577,10 @@ msgstr "Yayımcı kipi"
 | 
				
			|||||||
#~ msgid "JWT Algorithm"
 | 
					#~ msgid "JWT Algorithm"
 | 
				
			||||||
#~ msgstr "JWT Algoritması"
 | 
					#~ msgstr "JWT Algoritması"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: src/pages/providers/oauth2/OAuth2ProviderForm.ts
 | 
				
			||||||
 | 
					msgid "JWTs signed by certificates configured here can be used to authenticate to the provider."
 | 
				
			||||||
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: src/pages/providers/oauth2/OAuth2ProviderForm.ts
 | 
					#: src/pages/providers/oauth2/OAuth2ProviderForm.ts
 | 
				
			||||||
msgid "Key used to sign the tokens."
 | 
					msgid "Key used to sign the tokens."
 | 
				
			||||||
msgstr "Anahtar belirteçleri imzalamak için kullanılır."
 | 
					msgstr "Anahtar belirteçleri imzalamak için kullanılır."
 | 
				
			||||||
@ -2739,6 +2744,7 @@ msgstr "Yükleniyor"
 | 
				
			|||||||
#: src/pages/providers/oauth2/OAuth2ProviderForm.ts
 | 
					#: src/pages/providers/oauth2/OAuth2ProviderForm.ts
 | 
				
			||||||
#: src/pages/providers/oauth2/OAuth2ProviderForm.ts
 | 
					#: src/pages/providers/oauth2/OAuth2ProviderForm.ts
 | 
				
			||||||
#: src/pages/providers/oauth2/OAuth2ProviderForm.ts
 | 
					#: src/pages/providers/oauth2/OAuth2ProviderForm.ts
 | 
				
			||||||
 | 
					#: src/pages/providers/oauth2/OAuth2ProviderForm.ts
 | 
				
			||||||
#: src/pages/providers/proxy/ProxyProviderForm.ts
 | 
					#: src/pages/providers/proxy/ProxyProviderForm.ts
 | 
				
			||||||
#: src/pages/providers/proxy/ProxyProviderForm.ts
 | 
					#: src/pages/providers/proxy/ProxyProviderForm.ts
 | 
				
			||||||
#: src/pages/providers/proxy/ProxyProviderForm.ts
 | 
					#: src/pages/providers/proxy/ProxyProviderForm.ts
 | 
				
			||||||
@ -5902,6 +5908,10 @@ msgstr "Doğrulama"
 | 
				
			|||||||
msgid "Verification Certificate"
 | 
					msgid "Verification Certificate"
 | 
				
			||||||
msgstr "Doğrulama Sertifikası"
 | 
					msgstr "Doğrulama Sertifikası"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: src/pages/providers/oauth2/OAuth2ProviderForm.ts
 | 
				
			||||||
 | 
					msgid "Verification certificates"
 | 
				
			||||||
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: src/pages/stages/email/EmailStageForm.ts
 | 
					#: src/pages/stages/email/EmailStageForm.ts
 | 
				
			||||||
msgid "Verify the user's email address by sending them a one-time-link. Can also be used for recovery to verify the user's authenticity."
 | 
					msgid "Verify the user's email address by sending them a one-time-link. Can also be used for recovery to verify the user's authenticity."
 | 
				
			||||||
msgstr "Kullanıcının e-posta adresini bir kerelik bağlantı göndererek doğrulayın. Kullanıcının orijinalliğini doğrulamak için kurtarma için de kullanılabilir."
 | 
					msgstr "Kullanıcının e-posta adresini bir kerelik bağlantı göndererek doğrulayın. Kullanıcının orijinalliğini doğrulamak için kurtarma için de kullanılabilir."
 | 
				
			||||||
 | 
				
			|||||||
@ -2333,6 +2333,7 @@ msgstr "隐藏服务账户"
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#: src/pages/events/RuleForm.ts src/pages/outposts/OutpostForm.ts
 | 
					#: src/pages/events/RuleForm.ts src/pages/outposts/OutpostForm.ts
 | 
				
			||||||
#: src/pages/providers/oauth2/OAuth2ProviderForm.ts
 | 
					#: src/pages/providers/oauth2/OAuth2ProviderForm.ts
 | 
				
			||||||
 | 
					#: src/pages/providers/oauth2/OAuth2ProviderForm.ts
 | 
				
			||||||
#: src/pages/providers/proxy/ProxyProviderForm.ts
 | 
					#: src/pages/providers/proxy/ProxyProviderForm.ts
 | 
				
			||||||
#: src/pages/providers/saml/SAMLProviderForm.ts
 | 
					#: src/pages/providers/saml/SAMLProviderForm.ts
 | 
				
			||||||
#: src/pages/sources/ldap/LDAPSourceForm.ts
 | 
					#: src/pages/sources/ldap/LDAPSourceForm.ts
 | 
				
			||||||
@ -2612,6 +2613,10 @@ msgstr "Issuer 模式"
 | 
				
			|||||||
#~ msgid "JWT Algorithm"
 | 
					#~ msgid "JWT Algorithm"
 | 
				
			||||||
#~ msgstr "JWT 算法"
 | 
					#~ msgstr "JWT 算法"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: src/pages/providers/oauth2/OAuth2ProviderForm.ts
 | 
				
			||||||
 | 
					msgid "JWTs signed by certificates configured here can be used to authenticate to the provider."
 | 
				
			||||||
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: src/pages/providers/oauth2/OAuth2ProviderForm.ts
 | 
					#: src/pages/providers/oauth2/OAuth2ProviderForm.ts
 | 
				
			||||||
msgid "Key used to sign the tokens."
 | 
					msgid "Key used to sign the tokens."
 | 
				
			||||||
msgstr "用于签名令牌的密钥。"
 | 
					msgstr "用于签名令牌的密钥。"
 | 
				
			||||||
@ -2771,6 +2776,7 @@ msgstr "正在加载"
 | 
				
			|||||||
#: src/pages/providers/oauth2/OAuth2ProviderForm.ts
 | 
					#: src/pages/providers/oauth2/OAuth2ProviderForm.ts
 | 
				
			||||||
#: src/pages/providers/oauth2/OAuth2ProviderForm.ts
 | 
					#: src/pages/providers/oauth2/OAuth2ProviderForm.ts
 | 
				
			||||||
#: src/pages/providers/oauth2/OAuth2ProviderForm.ts
 | 
					#: src/pages/providers/oauth2/OAuth2ProviderForm.ts
 | 
				
			||||||
 | 
					#: src/pages/providers/oauth2/OAuth2ProviderForm.ts
 | 
				
			||||||
#: src/pages/providers/proxy/ProxyProviderForm.ts
 | 
					#: src/pages/providers/proxy/ProxyProviderForm.ts
 | 
				
			||||||
#: src/pages/providers/proxy/ProxyProviderForm.ts
 | 
					#: src/pages/providers/proxy/ProxyProviderForm.ts
 | 
				
			||||||
#: src/pages/providers/proxy/ProxyProviderForm.ts
 | 
					#: src/pages/providers/proxy/ProxyProviderForm.ts
 | 
				
			||||||
@ -6015,6 +6021,10 @@ msgstr "验证"
 | 
				
			|||||||
msgid "Verification Certificate"
 | 
					msgid "Verification Certificate"
 | 
				
			||||||
msgstr "验证证书"
 | 
					msgstr "验证证书"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: src/pages/providers/oauth2/OAuth2ProviderForm.ts
 | 
				
			||||||
 | 
					msgid "Verification certificates"
 | 
				
			||||||
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: src/pages/stages/email/EmailStageForm.ts
 | 
					#: src/pages/stages/email/EmailStageForm.ts
 | 
				
			||||||
msgid ""
 | 
					msgid ""
 | 
				
			||||||
"Verify the user's email address by sending them a one-time-link. Can also be"
 | 
					"Verify the user's email address by sending them a one-time-link. Can also be"
 | 
				
			||||||
 | 
				
			|||||||
@ -2332,6 +2332,7 @@ msgstr "隐藏服务账户"
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#: src/pages/events/RuleForm.ts src/pages/outposts/OutpostForm.ts
 | 
					#: src/pages/events/RuleForm.ts src/pages/outposts/OutpostForm.ts
 | 
				
			||||||
#: src/pages/providers/oauth2/OAuth2ProviderForm.ts
 | 
					#: src/pages/providers/oauth2/OAuth2ProviderForm.ts
 | 
				
			||||||
 | 
					#: src/pages/providers/oauth2/OAuth2ProviderForm.ts
 | 
				
			||||||
#: src/pages/providers/proxy/ProxyProviderForm.ts
 | 
					#: src/pages/providers/proxy/ProxyProviderForm.ts
 | 
				
			||||||
#: src/pages/providers/saml/SAMLProviderForm.ts
 | 
					#: src/pages/providers/saml/SAMLProviderForm.ts
 | 
				
			||||||
#: src/pages/sources/ldap/LDAPSourceForm.ts
 | 
					#: src/pages/sources/ldap/LDAPSourceForm.ts
 | 
				
			||||||
@ -2611,6 +2612,10 @@ msgstr "Issuer mode"
 | 
				
			|||||||
#~ msgid "JWT Algorithm"
 | 
					#~ msgid "JWT Algorithm"
 | 
				
			||||||
#~ msgstr "JWT 算法"
 | 
					#~ msgstr "JWT 算法"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: src/pages/providers/oauth2/OAuth2ProviderForm.ts
 | 
				
			||||||
 | 
					msgid "JWTs signed by certificates configured here can be used to authenticate to the provider."
 | 
				
			||||||
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: src/pages/providers/oauth2/OAuth2ProviderForm.ts
 | 
					#: src/pages/providers/oauth2/OAuth2ProviderForm.ts
 | 
				
			||||||
msgid "Key used to sign the tokens."
 | 
					msgid "Key used to sign the tokens."
 | 
				
			||||||
msgstr "用于对令牌进行签名的密钥。"
 | 
					msgstr "用于对令牌进行签名的密钥。"
 | 
				
			||||||
@ -2770,6 +2775,7 @@ msgstr "正在加载"
 | 
				
			|||||||
#: src/pages/providers/oauth2/OAuth2ProviderForm.ts
 | 
					#: src/pages/providers/oauth2/OAuth2ProviderForm.ts
 | 
				
			||||||
#: src/pages/providers/oauth2/OAuth2ProviderForm.ts
 | 
					#: src/pages/providers/oauth2/OAuth2ProviderForm.ts
 | 
				
			||||||
#: src/pages/providers/oauth2/OAuth2ProviderForm.ts
 | 
					#: src/pages/providers/oauth2/OAuth2ProviderForm.ts
 | 
				
			||||||
 | 
					#: src/pages/providers/oauth2/OAuth2ProviderForm.ts
 | 
				
			||||||
#: src/pages/providers/proxy/ProxyProviderForm.ts
 | 
					#: src/pages/providers/proxy/ProxyProviderForm.ts
 | 
				
			||||||
#: src/pages/providers/proxy/ProxyProviderForm.ts
 | 
					#: src/pages/providers/proxy/ProxyProviderForm.ts
 | 
				
			||||||
#: src/pages/providers/proxy/ProxyProviderForm.ts
 | 
					#: src/pages/providers/proxy/ProxyProviderForm.ts
 | 
				
			||||||
@ -6015,6 +6021,10 @@ msgstr "验证"
 | 
				
			|||||||
msgid "Verification Certificate"
 | 
					msgid "Verification Certificate"
 | 
				
			||||||
msgstr "验证证书"
 | 
					msgstr "验证证书"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: src/pages/providers/oauth2/OAuth2ProviderForm.ts
 | 
				
			||||||
 | 
					msgid "Verification certificates"
 | 
				
			||||||
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: src/pages/stages/email/EmailStageForm.ts
 | 
					#: src/pages/stages/email/EmailStageForm.ts
 | 
				
			||||||
msgid ""
 | 
					msgid ""
 | 
				
			||||||
"Verify the user's email address by sending them a one-time-link. Can also be"
 | 
					"Verify the user's email address by sending them a one-time-link. Can also be"
 | 
				
			||||||
 | 
				
			|||||||
@ -2332,6 +2332,7 @@ msgstr "隐藏服务账户"
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#: src/pages/events/RuleForm.ts src/pages/outposts/OutpostForm.ts
 | 
					#: src/pages/events/RuleForm.ts src/pages/outposts/OutpostForm.ts
 | 
				
			||||||
#: src/pages/providers/oauth2/OAuth2ProviderForm.ts
 | 
					#: src/pages/providers/oauth2/OAuth2ProviderForm.ts
 | 
				
			||||||
 | 
					#: src/pages/providers/oauth2/OAuth2ProviderForm.ts
 | 
				
			||||||
#: src/pages/providers/proxy/ProxyProviderForm.ts
 | 
					#: src/pages/providers/proxy/ProxyProviderForm.ts
 | 
				
			||||||
#: src/pages/providers/saml/SAMLProviderForm.ts
 | 
					#: src/pages/providers/saml/SAMLProviderForm.ts
 | 
				
			||||||
#: src/pages/sources/ldap/LDAPSourceForm.ts
 | 
					#: src/pages/sources/ldap/LDAPSourceForm.ts
 | 
				
			||||||
@ -2611,6 +2612,10 @@ msgstr "Issuer mode"
 | 
				
			|||||||
#~ msgid "JWT Algorithm"
 | 
					#~ msgid "JWT Algorithm"
 | 
				
			||||||
#~ msgstr "JWT 算法"
 | 
					#~ msgstr "JWT 算法"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: src/pages/providers/oauth2/OAuth2ProviderForm.ts
 | 
				
			||||||
 | 
					msgid "JWTs signed by certificates configured here can be used to authenticate to the provider."
 | 
				
			||||||
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: src/pages/providers/oauth2/OAuth2ProviderForm.ts
 | 
					#: src/pages/providers/oauth2/OAuth2ProviderForm.ts
 | 
				
			||||||
msgid "Key used to sign the tokens."
 | 
					msgid "Key used to sign the tokens."
 | 
				
			||||||
msgstr "用于对令牌进行签名的密钥。"
 | 
					msgstr "用于对令牌进行签名的密钥。"
 | 
				
			||||||
@ -2770,6 +2775,7 @@ msgstr "正在加载"
 | 
				
			|||||||
#: src/pages/providers/oauth2/OAuth2ProviderForm.ts
 | 
					#: src/pages/providers/oauth2/OAuth2ProviderForm.ts
 | 
				
			||||||
#: src/pages/providers/oauth2/OAuth2ProviderForm.ts
 | 
					#: src/pages/providers/oauth2/OAuth2ProviderForm.ts
 | 
				
			||||||
#: src/pages/providers/oauth2/OAuth2ProviderForm.ts
 | 
					#: src/pages/providers/oauth2/OAuth2ProviderForm.ts
 | 
				
			||||||
 | 
					#: src/pages/providers/oauth2/OAuth2ProviderForm.ts
 | 
				
			||||||
#: src/pages/providers/proxy/ProxyProviderForm.ts
 | 
					#: src/pages/providers/proxy/ProxyProviderForm.ts
 | 
				
			||||||
#: src/pages/providers/proxy/ProxyProviderForm.ts
 | 
					#: src/pages/providers/proxy/ProxyProviderForm.ts
 | 
				
			||||||
#: src/pages/providers/proxy/ProxyProviderForm.ts
 | 
					#: src/pages/providers/proxy/ProxyProviderForm.ts
 | 
				
			||||||
@ -6015,6 +6021,10 @@ msgstr "验证"
 | 
				
			|||||||
msgid "Verification Certificate"
 | 
					msgid "Verification Certificate"
 | 
				
			||||||
msgstr "验证证书"
 | 
					msgstr "验证证书"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: src/pages/providers/oauth2/OAuth2ProviderForm.ts
 | 
				
			||||||
 | 
					msgid "Verification certificates"
 | 
				
			||||||
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: src/pages/stages/email/EmailStageForm.ts
 | 
					#: src/pages/stages/email/EmailStageForm.ts
 | 
				
			||||||
msgid ""
 | 
					msgid ""
 | 
				
			||||||
"Verify the user's email address by sending them a one-time-link. Can also be"
 | 
					"Verify the user's email address by sending them a one-time-link. Can also be"
 | 
				
			||||||
 | 
				
			|||||||
@ -117,7 +117,7 @@ export class CertificateKeyPairListPage extends TablePage<CertificateKeyPair> {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    renderExpanded(item: CertificateKeyPair): TemplateResult {
 | 
					    renderExpanded(item: CertificateKeyPair): TemplateResult {
 | 
				
			||||||
        return html`<td role="cell" colspan="3">
 | 
					        return html`<td role="cell" colspan="4">
 | 
				
			||||||
                <div class="pf-c-table__expandable-row-content">
 | 
					                <div class="pf-c-table__expandable-row-content">
 | 
				
			||||||
                    <dl class="pf-c-description-list pf-m-horizontal">
 | 
					                    <dl class="pf-c-description-list pf-m-horizontal">
 | 
				
			||||||
                        <div class="pf-c-description-list__group">
 | 
					                        <div class="pf-c-description-list__group">
 | 
				
			||||||
 | 
				
			|||||||
@ -292,6 +292,41 @@ ${this.instance?.redirectUris}</textarea
 | 
				
			|||||||
                            ${t`Hold control/command to select multiple items.`}
 | 
					                            ${t`Hold control/command to select multiple items.`}
 | 
				
			||||||
                        </p>
 | 
					                        </p>
 | 
				
			||||||
                    </ak-form-element-horizontal>
 | 
					                    </ak-form-element-horizontal>
 | 
				
			||||||
 | 
					                    <ak-form-element-horizontal
 | 
				
			||||||
 | 
					                        label=${t`Verification certificates`}
 | 
				
			||||||
 | 
					                        name="verificationKeys"
 | 
				
			||||||
 | 
					                    >
 | 
				
			||||||
 | 
					                        <select class="pf-c-form-control" multiple>
 | 
				
			||||||
 | 
					                            ${until(
 | 
				
			||||||
 | 
					                                new CryptoApi(DEFAULT_CONFIG)
 | 
				
			||||||
 | 
					                                    .cryptoCertificatekeypairsList({
 | 
				
			||||||
 | 
					                                        ordering: "name",
 | 
				
			||||||
 | 
					                                    })
 | 
				
			||||||
 | 
					                                    .then((keys) => {
 | 
				
			||||||
 | 
					                                        return keys.results.map((key) => {
 | 
				
			||||||
 | 
					                                            const selected = (
 | 
				
			||||||
 | 
					                                                this.instance?.verificationKeys || []
 | 
				
			||||||
 | 
					                                            ).some((su) => {
 | 
				
			||||||
 | 
					                                                return su == key.pk;
 | 
				
			||||||
 | 
					                                            });
 | 
				
			||||||
 | 
					                                            return html`<option
 | 
				
			||||||
 | 
					                                                value=${key.pk}
 | 
				
			||||||
 | 
					                                                ?selected=${selected}
 | 
				
			||||||
 | 
					                                            >
 | 
				
			||||||
 | 
					                                                ${key.name} (${key.privateKeyType?.toUpperCase()})
 | 
				
			||||||
 | 
					                                            </option>`;
 | 
				
			||||||
 | 
					                                        });
 | 
				
			||||||
 | 
					                                    }),
 | 
				
			||||||
 | 
					                                html`<option>${t`Loading...`}</option>`,
 | 
				
			||||||
 | 
					                            )}
 | 
				
			||||||
 | 
					                        </select>
 | 
				
			||||||
 | 
					                        <p class="pf-c-form__helper-text">
 | 
				
			||||||
 | 
					                            ${t`JWTs signed by certificates configured here can be used to authenticate to the provider.`}
 | 
				
			||||||
 | 
					                        </p>
 | 
				
			||||||
 | 
					                        <p class="pf-c-form__helper-text">
 | 
				
			||||||
 | 
					                            ${t`Hold control/command to select multiple items.`}
 | 
				
			||||||
 | 
					                        </p>
 | 
				
			||||||
 | 
					                    </ak-form-element-horizontal>
 | 
				
			||||||
                    <ak-form-element-horizontal
 | 
					                    <ak-form-element-horizontal
 | 
				
			||||||
                        label=${t`Subject mode`}
 | 
					                        label=${t`Subject mode`}
 | 
				
			||||||
                        ?required=${true}
 | 
					                        ?required=${true}
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										53
									
								
								website/docs/providers/oauth2/client_credentials.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										53
									
								
								website/docs/providers/oauth2/client_credentials.md
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,53 @@
 | 
				
			|||||||
 | 
					# Machine-to-machine authentication
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Client credentials can be used for machine-to-machine communication authentication. Clients can authenticate themselves using service-accounts; standard client_id + client_secret is not sufficient. This behavior is due to providers only being able to have a single secret at any given time.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Static authentication
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Hence identification is based on service-accounts, and authentication is based on App-password tokens. These objects can be created in a single step using the *Create Service account* function.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					An example request can look like this:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					POST /application/o/token/ HTTP/1.1
 | 
				
			||||||
 | 
					Host: authentik.company
 | 
				
			||||||
 | 
					Content-Type: application/x-www-form-urlencoded
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					grant_type=client_credentials&
 | 
				
			||||||
 | 
					client_id=application_client_id&
 | 
				
			||||||
 | 
					username=my-service-account&
 | 
				
			||||||
 | 
					password=my-token
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					This will return a JSON response with an `access_token`, which is a signed JWT token. This token can be sent along requests to other hosts, which can then validate the JWT based on the signing key configured in authentik.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### JWT-authentication
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Starting with authentik 2022.4, you can authenticate and get a token using an existing JWT.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					(For readability we will refer to the JWT issued by the external issuer/platform as input JWT, and the resulting JWT from authentik as the output JWT)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					To configure this, the certificate used to sign the input JWT must be created in authentik. The certificate is enough, a private key is not required. Afterwards, configure the certificate in the OAuth2 provider settings under *Verification certificates*.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					With this configure, any JWT issued by the configured certificates can be used to authenticate:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					POST /application/o/token/ HTTP/1.1
 | 
				
			||||||
 | 
					Host: authentik.company
 | 
				
			||||||
 | 
					Content-Type: application/x-www-form-urlencoded
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					grant_type=client_credentials&
 | 
				
			||||||
 | 
					client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer&
 | 
				
			||||||
 | 
					client_assertion=$inputJWT&
 | 
				
			||||||
 | 
					client_id=application_client_id
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Alternatively, you can set the `client_secret` parameter to the `$inputJWT`, for applications which can set the password from a file but not other parameters.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Input JWTs are checked to be signed by any of the selected *Verification certificates*, and their `exp` attribute must not be now or in the past.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					To do additional checks, you can use *[Expression policies](../../policies/expression)*:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```python
 | 
				
			||||||
 | 
					return request.context["JWT"]["iss"] == "https://my.issuer"
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
@ -4,7 +4,7 @@ title: OAuth2 Provider
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
This provider supports both generic OAuth2 as well as OpenID Connect
 | 
					This provider supports both generic OAuth2 as well as OpenID Connect
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Scopes can be configured using Scope Mappings, a type of [Property Mappings](../property-mappings/#scope-mapping).
 | 
					Scopes can be configured using Scope Mappings, a type of [Property Mappings](../../property-mappings/#scope-mapping).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| Endpoint             | URL                                                                  |
 | 
					| Endpoint             | URL                                                                  |
 | 
				
			||||||
| -------------------- | -------------------------------------------------------------------- |
 | 
					| -------------------- | -------------------------------------------------------------------- |
 | 
				
			||||||
@ -42,18 +42,4 @@ Refresh tokens can be used as long-lived tokens to access user data, and further
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
### `client_credentials`:
 | 
					### `client_credentials`:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Client credentials can be used for machine-to-machine communication authentication. Clients can authenticate themselves using service-accounts; standard client_id + client_secret is not sufficient. This behavior is due to providers only being able to have a single secret at any given time.
 | 
					See [Machine-to-machine authentication](./client_credentials)
 | 
				
			||||||
 | 
					 | 
				
			||||||
Hence identification is based on service-accounts, and authentication is based on App-password tokens. These objects can be created in a single step using the *Create Service account* function.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
An example request can look like this:
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
```
 | 
					 | 
				
			||||||
POST /application/o/token/ HTTP/1.1
 | 
					 | 
				
			||||||
Host: authentik.company
 | 
					 | 
				
			||||||
Content-Type: application/x-www-form-urlencoded
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
grant_type=client_credentials&username=my-service-account&password=my-token&client_id=application_client_id
 | 
					 | 
				
			||||||
```
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
This will return a JSON response with an `access_token`, which is a signed JWT token. This token can be sent along requests to other hosts, which can then validate the JWT based on the signing key configured in authentik.
 | 
					 | 
				
			||||||
@ -73,4 +73,4 @@ This upgrade only applies if you are upgrading from a running 0.9 instance. auth
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
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.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Another side-effect of this upgrade is the change of OAuth2 URLs, see [here](../providers/oauth2.md).
 | 
					Another side-effect of this upgrade is the change of OAuth2 URLs, see [here](../providers/oauth2).
 | 
				
			||||||
 | 
				
			|||||||
@ -33,7 +33,14 @@ module.exports = {
 | 
				
			|||||||
            type: "category",
 | 
					            type: "category",
 | 
				
			||||||
            label: "Providers",
 | 
					            label: "Providers",
 | 
				
			||||||
            items: [
 | 
					            items: [
 | 
				
			||||||
                "providers/oauth2",
 | 
					                {
 | 
				
			||||||
 | 
					                    type: "category",
 | 
				
			||||||
 | 
					                    label: "OAuth2 Provider",
 | 
				
			||||||
 | 
					                    items: [
 | 
				
			||||||
 | 
					                        "providers/oauth2/index",
 | 
				
			||||||
 | 
					                        "providers/oauth2/client_credentials",
 | 
				
			||||||
 | 
					                    ],
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
                "providers/saml",
 | 
					                "providers/saml",
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    type: "category",
 | 
					                    type: "category",
 | 
				
			||||||
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user