providers/oauth2: remove jwt_alg field and set algorithm based on selected keypair, select HS256 when no keypair is selected

Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
This commit is contained in:
Jens Langhammer 2021-12-22 22:09:49 +01:00
parent 89696edbee
commit 2f3026084e
26 changed files with 126 additions and 205 deletions

View File

@ -146,7 +146,7 @@ class TestCrypto(APITestCase):
client_secret=generate_key(),
authorization_flow=create_test_flow(),
redirect_uris="http://localhost",
rsa_key=keypair,
signing_key=keypair,
)
response = self.client.get(
reverse(

View File

@ -7,25 +7,18 @@ from rest_framework.fields import CharField
from rest_framework.generics import get_object_or_404
from rest_framework.request import Request
from rest_framework.response import Response
from rest_framework.serializers import ValidationError
from rest_framework.viewsets import ModelViewSet
from authentik.core.api.providers import ProviderSerializer
from authentik.core.api.used_by import UsedByMixin
from authentik.core.api.utils import PassiveSerializer
from authentik.core.models import Provider
from authentik.providers.oauth2.models import JWTAlgorithms, OAuth2Provider
from authentik.providers.oauth2.models import OAuth2Provider
class OAuth2ProviderSerializer(ProviderSerializer):
"""OAuth2Provider Serializer"""
def validate_jwt_alg(self, value):
"""Ensure that when RS256 is selected, a certificate-key-pair is selected"""
if self.initial_data.get("rsa_key", None) is None and value == JWTAlgorithms.RS256:
raise ValidationError(_("RS256 requires a Certificate-Key-Pair to be selected."))
return value
class Meta:
model = OAuth2Provider
@ -37,8 +30,7 @@ class OAuth2ProviderSerializer(ProviderSerializer):
"access_code_validity",
"token_validity",
"include_claims_in_id_token",
"jwt_alg",
"rsa_key",
"signing_key",
"redirect_uris",
"sub_mode",
"property_mappings",
@ -73,8 +65,7 @@ class OAuth2ProviderViewSet(UsedByMixin, ModelViewSet):
"access_code_validity",
"token_validity",
"include_claims_in_id_token",
"jwt_alg",
"rsa_key",
"signing_key",
"redirect_uris",
"sub_mode",
"property_mappings",

View File

@ -0,0 +1,22 @@
# Generated by Django 4.0 on 2021-12-22 21:04
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('authentik_providers_oauth2', '0007_auto_20201016_1107_squashed_0017_alter_oauth2provider_token_validity'),
]
operations = [
migrations.RenameField(
model_name='oauth2provider',
old_name='rsa_key',
new_name='signing_key',
),
migrations.RemoveField(
model_name='oauth2provider',
name='jwt_alg',
),
]

View File

@ -8,6 +8,8 @@ from datetime import datetime
from hashlib import sha256
from typing import Any, Optional, Type
from urllib.parse import urlparse
from cryptography.hazmat.primitives.asymmetric.ec import EllipticCurvePrivateKey
from cryptography.hazmat.primitives.asymmetric.rsa import RSAPrivateKey
from dacite import from_dict
from django.db import models
@ -88,6 +90,7 @@ class JWTAlgorithms(models.TextChoices):
HS256 = "HS256", _("HS256 (Symmetric Encryption)")
RS256 = "RS256", _("RS256 (Asymmetric Encryption)")
EC256 = "EC256", _("EC256 (Asymmetric Encryption)")
class ScopeMapping(PropertyMapping):
@ -145,13 +148,6 @@ class OAuth2Provider(Provider):
verbose_name=_("Client Secret"),
default=generate_key,
)
jwt_alg = models.CharField(
max_length=10,
choices=JWTAlgorithms.choices,
default=JWTAlgorithms.RS256,
verbose_name=_("JWT Algorithm"),
help_text=_(JWTAlgorithms.__doc__),
)
redirect_uris = models.TextField(
default="",
blank=True,
@ -207,7 +203,7 @@ class OAuth2Provider(Provider):
help_text=_(("Configure how the issuer field of the ID Token should be filled.")),
)
rsa_key = models.ForeignKey(
signing_key = models.ForeignKey(
CertificateKeyPair,
verbose_name=_("RSA Key"),
on_delete=models.SET_NULL,
@ -231,29 +227,18 @@ class OAuth2Provider(Provider):
token.access_token = token.create_access_token(user, request)
return token
def get_jwt_key(self) -> str:
"""
Takes a provider and returns the set of keys associated with it.
Returns a list of keys.
"""
if self.jwt_alg == JWTAlgorithms.RS256:
# if the user selected RS256 but didn't select a
# CertificateKeyPair, we fall back to HS256
if not self.rsa_key:
Event.new(
EventAction.CONFIGURATION_ERROR,
provider=self,
message="Provider was configured for RS256, but no key was selected.",
).save()
self.jwt_alg = JWTAlgorithms.HS256
self.save()
else:
return self.rsa_key.key_data
if self.jwt_alg == JWTAlgorithms.HS256:
return self.client_secret
raise Exception("Unsupported key algorithm.")
def get_jwt_key(self) -> tuple[str, str]:
"""Get either the configured certificate or the client secret"""
if not self.signing_key:
# No Certificate at all, assume HS256
return self.client_secret, JWTAlgorithms.HS256
key: CertificateKeyPair = self.signing_key
private_key = key.private_key
if isinstance(private_key, RSAPrivateKey):
return key.key_data, JWTAlgorithms.RS256
if isinstance(private_key, EllipticCurvePrivateKey):
return key.key_data, JWTAlgorithms.EC256
raise Exception(f"Invalid private key type: {type(private_key)}")
def get_issuer(self, request: HttpRequest) -> Optional[str]:
"""Get issuer, based on request"""
@ -293,13 +278,13 @@ class OAuth2Provider(Provider):
def encode(self, payload: dict[str, Any]) -> str:
"""Represent the ID Token as a JSON Web Token (JWT)."""
headers = {}
if self.rsa_key:
headers["kid"] = self.rsa_key.kid
key = self.get_jwt_key()
if self.signing_key:
headers["kid"] = self.signing_key.kid
key, alg = self.get_jwt_key()
# If the provider does not have an RSA Key assigned, it was switched to Symmetric
self.refresh_from_db()
# pyright: reportGeneralTypeIssues=false
return encode(payload, key, algorithm=self.jwt_alg, headers=headers)
return encode(payload, key, algorithm=alg, headers=headers)
class Meta:

View File

@ -1,32 +0,0 @@
"""Test oauth2 provider API"""
from django.urls import reverse
from rest_framework.test import APITestCase
from authentik.core.tests.utils import create_test_admin_user, create_test_flow
from authentik.providers.oauth2.models import JWTAlgorithms
class TestOAuth2ProviderAPI(APITestCase):
"""Test oauth2 provider API"""
def setUp(self) -> None:
super().setUp()
self.user = create_test_admin_user()
self.client.force_login(self.user)
def test_validate(self):
"""Test OAuth2 Provider validation"""
response = self.client.post(
reverse(
"authentik_api:oauth2provider-list",
),
data={
"name": "test",
"jwt_alg": str(JWTAlgorithms.RS256),
"authorization_flow": create_test_flow().pk,
},
)
self.assertJSONEqual(
response.content.decode(),
{"jwt_alg": ["RS256 requires a Certificate-Key-Pair to be selected."]},
)

View File

@ -218,7 +218,7 @@ class TestAuthorize(OAuthTestCase):
client_secret=generate_key(),
authorization_flow=flow,
redirect_uris="http://localhost",
rsa_key=create_test_cert(),
signing_key=create_test_cert(),
)
Application.objects.create(name="app", slug="app", provider=provider)
state = generate_id()

View File

@ -25,7 +25,7 @@ class TestJWKS(OAuthTestCase):
client_id="test",
authorization_flow=create_test_flow(),
redirect_uris="http://local.invalid",
rsa_key=create_test_cert(),
signing_key=create_test_cert(),
)
app = Application.objects.create(name="test", slug="test", provider=provider)
response = self.client.get(

View File

@ -35,7 +35,7 @@ class TestToken(OAuthTestCase):
client_secret=generate_key(),
authorization_flow=create_test_flow(),
redirect_uris="http://testserver",
rsa_key=create_test_cert(),
signing_key=create_test_cert(),
)
header = b64encode(f"{provider.client_id}:{provider.client_secret}".encode()).decode()
user = create_test_admin_user()
@ -62,7 +62,7 @@ class TestToken(OAuthTestCase):
client_secret=generate_key(),
authorization_flow=create_test_flow(),
redirect_uris="http://testserver",
rsa_key=create_test_cert(),
signing_key=create_test_cert(),
)
header = b64encode(f"{provider.client_id}:{provider.client_secret}".encode()).decode()
request = self.factory.post(
@ -85,7 +85,7 @@ class TestToken(OAuthTestCase):
client_secret=generate_key(),
authorization_flow=create_test_flow(),
redirect_uris="http://local.invalid",
rsa_key=create_test_cert(),
signing_key=create_test_cert(),
)
header = b64encode(f"{provider.client_id}:{provider.client_secret}".encode()).decode()
user = create_test_admin_user()
@ -114,7 +114,7 @@ class TestToken(OAuthTestCase):
client_secret=generate_key(),
authorization_flow=create_test_flow(),
redirect_uris="http://local.invalid",
rsa_key=create_test_cert(),
signing_key=create_test_cert(),
)
# Needs to be assigned to an application for iss to be set
self.app.provider = provider
@ -156,7 +156,7 @@ class TestToken(OAuthTestCase):
client_secret=generate_key(),
authorization_flow=create_test_flow(),
redirect_uris="http://local.invalid",
rsa_key=create_test_cert(),
signing_key=create_test_cert(),
)
# Needs to be assigned to an application for iss to be set
self.app.provider = provider
@ -205,7 +205,7 @@ class TestToken(OAuthTestCase):
client_secret=generate_key(),
authorization_flow=create_test_flow(),
redirect_uris="http://local.invalid",
rsa_key=create_test_cert(),
signing_key=create_test_cert(),
)
header = b64encode(f"{provider.client_id}:{provider.client_secret}".encode()).decode()
user = create_test_admin_user()
@ -250,7 +250,7 @@ class TestToken(OAuthTestCase):
client_secret=generate_key(),
authorization_flow=create_test_flow(),
redirect_uris="http://testserver",
rsa_key=create_test_cert(),
signing_key=create_test_cert(),
)
# Needs to be assigned to an application for iss to be set
self.app.provider = provider

View File

@ -27,7 +27,7 @@ class TestUserinfo(OAuthTestCase):
client_secret=generate_key(),
authorization_flow=create_test_flow(),
redirect_uris="",
rsa_key=create_test_cert(),
signing_key=create_test_cert(),
)
self.provider.property_mappings.set(ScopeMapping.objects.all())
# Needs to be assigned to an application for iss to be set

View File

@ -2,7 +2,7 @@
from django.test import TestCase
from jwt import decode
from authentik.providers.oauth2.models import JWTAlgorithms, OAuth2Provider, RefreshToken
from authentik.providers.oauth2.models import OAuth2Provider, RefreshToken
class OAuthTestCase(TestCase):
@ -19,13 +19,11 @@ class OAuthTestCase(TestCase):
def validate_jwt(self, token: RefreshToken, provider: OAuth2Provider):
"""Validate that all required fields are set"""
key = provider.client_secret
if provider.jwt_alg == JWTAlgorithms.RS256:
key = provider.rsa_key.public_key
key, alg = provider.get_jwt_key()
jwt = decode(
token.access_token,
key,
algorithms=[provider.jwt_alg],
algorithms=[alg],
audience=provider.client_id,
)
id_token = token.id_token.to_dict()

View File

@ -1,7 +1,8 @@
"""authentik OAuth2 JWKS Views"""
from base64 import urlsafe_b64encode
from cryptography.hazmat.primitives.asymmetric.ec import EllipticCurvePrivateKey, EllipticCurvePublicKey
from cryptography.hazmat.primitives.asymmetric.rsa import RSAPublicKey
from cryptography.hazmat.primitives.asymmetric.rsa import RSAPrivateKey, RSAPublicKey
from django.http import HttpRequest, HttpResponse, JsonResponse
from django.shortcuts import get_object_or_404
from django.views import View
@ -25,23 +26,39 @@ class JWKSView(View):
"""Show RSA Key data for Provider"""
application = get_object_or_404(Application, slug=application_slug)
provider: OAuth2Provider = get_object_or_404(OAuth2Provider, pk=application.provider_id)
private_key = provider.signing_key
response_data = {}
if provider.jwt_alg == JWTAlgorithms.RS256 and provider.rsa_key:
public_key: RSAPublicKey = provider.rsa_key.private_key.public_key()
if private_key:
if isinstance(private_key, RSAPrivateKey):
public_key: RSAPublicKey = private_key.public_key()
public_numbers = public_key.public_numbers()
response_data["keys"] = [
{
"kty": "RSA",
"alg": "RS256",
"alg": JWTAlgorithms.RS256,
"use": "sig",
"kid": provider.rsa_key.kid,
"kid": private_key.kid,
"n": b64_enc(public_numbers.n),
"e": b64_enc(public_numbers.e),
}
]
elif isinstance(private_key, EllipticCurvePrivateKey):
public_key: EllipticCurvePublicKey = private_key.public_key()
public_numbers = public_key.public_numbers()
response_data["keys"] = [
{
"kty": "EC",
"alg": JWTAlgorithms.EC256,
"use": "sig",
"kid": private_key.kid,
"n": b64_enc(public_numbers.n),
"e": b64_enc(public_numbers.e),
}
]
response = JsonResponse(response_data)
response["Access-Control-Allow-Origin"] = "*"

View File

@ -39,6 +39,7 @@ class ProviderInfoView(View):
)
if SCOPE_OPENID not in scopes:
scopes.append(SCOPE_OPENID)
_, supported_alg = provider.get_jwt_key()
return {
"issuer": provider.get_issuer(self.request),
"authorization_endpoint": self.request.build_absolute_uri(
@ -78,7 +79,7 @@ class ProviderInfoView(View):
GRANT_TYPE_REFRESH_TOKEN,
GrantTypes.IMPLICIT,
],
"id_token_signing_alg_values_supported": [provider.jwt_alg],
"id_token_signing_alg_values_supported": [supported_alg],
# See: http://openid.net/specs/openid-connect-core-1_0.html#SubjectIDTypes
"subject_types_supported": ["public"],
"token_endpoint_auth_methods_supported": [

View File

@ -18,7 +18,6 @@ from authentik.providers.oauth2.constants import (
)
from authentik.providers.oauth2.models import (
ClientTypes,
JWTAlgorithms,
OAuth2Provider,
ScopeMapping,
)
@ -128,8 +127,7 @@ class ProxyProvider(OutpostModel, OAuth2Provider):
def set_oauth_defaults(self):
"""Ensure all OAuth2-related settings are correct"""
self.client_type = ClientTypes.CONFIDENTIAL
self.jwt_alg = JWTAlgorithms.HS256
self.rsa_key = None
self.signing_key = None
scopes = ScopeMapping.objects.filter(
scope_name__in=[
SCOPE_OPENID,

View File

@ -10858,15 +10858,6 @@ paths:
- global
- per_provider
description: Configure how the issuer field of the ID Token should be filled.
- in: query
name: jwt_alg
schema:
type: string
title: JWT Algorithm
enum:
- HS256
- RS256
description: Algorithm used to sign the JWT Token
- in: query
name: name
schema:
@ -10902,17 +10893,17 @@ paths:
name: redirect_uris
schema:
type: string
- in: query
name: rsa_key
schema:
type: string
format: uuid
- name: search
required: false
in: query
description: A search term.
schema:
type: string
- in: query
name: signing_key
schema:
type: string
format: uuid
- in: query
name: sub_mode
schema:
@ -22221,11 +22212,6 @@ components:
- global
- per_provider
type: string
JwtAlgEnum:
enum:
- HS256
- RS256
type: string
KubernetesServiceConnection:
type: object
description: KubernetesServiceConnection Serializer
@ -23099,15 +23085,11 @@ components:
type: boolean
description: Include User claims from scopes in the id_token, for applications
that don't access the userinfo endpoint.
jwt_alg:
allOf:
- $ref: '#/components/schemas/JwtAlgEnum'
title: JWT Algorithm
description: Algorithm used to sign the JWT Token
rsa_key:
signing_key:
type: string
format: uuid
nullable: true
title: RSA Key
description: Key used to sign the tokens. Only required when JWT Algorithm
is set to RS256.
redirect_uris:
@ -23175,15 +23157,11 @@ components:
type: boolean
description: Include User claims from scopes in the id_token, for applications
that don't access the userinfo endpoint.
jwt_alg:
allOf:
- $ref: '#/components/schemas/JwtAlgEnum'
title: JWT Algorithm
description: Algorithm used to sign the JWT Token
rsa_key:
signing_key:
type: string
format: uuid
nullable: true
title: RSA Key
description: Key used to sign the tokens. Only required when JWT Algorithm
is set to RS256.
redirect_uris:
@ -27509,15 +27487,11 @@ components:
type: boolean
description: Include User claims from scopes in the id_token, for applications
that don't access the userinfo endpoint.
jwt_alg:
allOf:
- $ref: '#/components/schemas/JwtAlgEnum'
title: JWT Algorithm
description: Algorithm used to sign the JWT Token
rsa_key:
signing_key:
type: string
format: uuid
nullable: true
title: RSA Key
description: Key used to sign the tokens. Only required when JWT Algorithm
is set to RS256.
redirect_uris:

View File

@ -81,7 +81,7 @@ class TestProviderOAuth2OAuth(SeleniumTestCase):
client_type=ClientTypes.CONFIDENTIAL,
client_id=self.client_id,
client_secret=self.client_secret,
rsa_key=create_test_cert(),
signing_key=create_test_cert(),
redirect_uris="http://localhost:3000/",
authorization_flow=authorization_flow,
)
@ -123,7 +123,7 @@ class TestProviderOAuth2OAuth(SeleniumTestCase):
client_type=ClientTypes.CONFIDENTIAL,
client_id=self.client_id,
client_secret=self.client_secret,
rsa_key=create_test_cert(),
signing_key=create_test_cert(),
redirect_uris="http://localhost:3000/login/generic_oauth",
authorization_flow=authorization_flow,
)
@ -178,7 +178,7 @@ class TestProviderOAuth2OAuth(SeleniumTestCase):
client_type=ClientTypes.CONFIDENTIAL,
client_id=self.client_id,
client_secret=self.client_secret,
rsa_key=create_test_cert(),
signing_key=create_test_cert(),
redirect_uris="http://localhost:3000/login/generic_oauth",
authorization_flow=authorization_flow,
)
@ -243,7 +243,7 @@ class TestProviderOAuth2OAuth(SeleniumTestCase):
client_type=ClientTypes.CONFIDENTIAL,
client_id=self.client_id,
client_secret=self.client_secret,
rsa_key=create_test_cert(),
signing_key=create_test_cert(),
redirect_uris="http://localhost:3000/login/generic_oauth",
)
provider.property_mappings.set(
@ -315,7 +315,7 @@ class TestProviderOAuth2OAuth(SeleniumTestCase):
client_type=ClientTypes.CONFIDENTIAL,
client_id=self.client_id,
client_secret=self.client_secret,
rsa_key=create_test_cert(),
signing_key=create_test_cert(),
redirect_uris="http://localhost:3000/login/generic_oauth",
)
provider.property_mappings.set(

View File

@ -80,7 +80,7 @@ class TestProviderOAuth2OIDC(SeleniumTestCase):
client_type=ClientTypes.CONFIDENTIAL,
client_id=self.client_id,
client_secret=self.client_secret,
rsa_key=create_test_cert(),
signing_key=create_test_cert(),
redirect_uris="http://localhost:9009/",
authorization_flow=authorization_flow,
)
@ -122,7 +122,7 @@ class TestProviderOAuth2OIDC(SeleniumTestCase):
client_type=ClientTypes.CONFIDENTIAL,
client_id=self.client_id,
client_secret=self.client_secret,
rsa_key=create_test_cert(),
signing_key=create_test_cert(),
redirect_uris="http://localhost:9009/auth/callback",
authorization_flow=authorization_flow,
)
@ -172,7 +172,7 @@ class TestProviderOAuth2OIDC(SeleniumTestCase):
client_type=ClientTypes.CONFIDENTIAL,
client_id=self.client_id,
client_secret=self.client_secret,
rsa_key=create_test_cert(),
signing_key=create_test_cert(),
redirect_uris="http://localhost:9009/auth/callback",
)
provider.property_mappings.set(
@ -235,7 +235,7 @@ class TestProviderOAuth2OIDC(SeleniumTestCase):
client_type=ClientTypes.CONFIDENTIAL,
client_id=self.client_id,
client_secret=self.client_secret,
rsa_key=create_test_cert(),
signing_key=create_test_cert(),
redirect_uris="http://localhost:9009/auth/callback",
)
provider.property_mappings.set(

View File

@ -80,7 +80,7 @@ class TestProviderOAuth2OIDCImplicit(SeleniumTestCase):
client_type=ClientTypes.CONFIDENTIAL,
client_id=self.client_id,
client_secret=self.client_secret,
rsa_key=create_test_cert(),
signing_key=create_test_cert(),
redirect_uris="http://localhost:9009/",
authorization_flow=authorization_flow,
)
@ -122,7 +122,7 @@ class TestProviderOAuth2OIDCImplicit(SeleniumTestCase):
client_type=ClientTypes.CONFIDENTIAL,
client_id=self.client_id,
client_secret=self.client_secret,
rsa_key=create_test_cert(),
signing_key=create_test_cert(),
redirect_uris="http://localhost:9009/implicit/",
authorization_flow=authorization_flow,
)
@ -168,7 +168,7 @@ class TestProviderOAuth2OIDCImplicit(SeleniumTestCase):
client_type=ClientTypes.CONFIDENTIAL,
client_id=self.client_id,
client_secret=self.client_secret,
rsa_key=create_test_cert(),
signing_key=create_test_cert(),
redirect_uris="http://localhost:9009/implicit/",
)
provider.property_mappings.set(
@ -228,7 +228,7 @@ class TestProviderOAuth2OIDCImplicit(SeleniumTestCase):
client_type=ClientTypes.CONFIDENTIAL,
client_id=self.client_id,
client_secret=self.client_secret,
rsa_key=create_test_cert(),
signing_key=create_test_cert(),
redirect_uris="http://localhost:9009/implicit/",
)
provider.property_mappings.set(

View File

@ -175,9 +175,9 @@ ${this.instance?.redirectUris}</textarea
${t`If no explicit redirect URIs are specified, any redirect URI is allowed.`}
</p>
</ak-form-element-horizontal>
<ak-form-element-horizontal label=${t`RSA Key`} name="rsaKey">
<ak-form-element-horizontal label=${t`Signing Key`} name="signingKey">
<select class="pf-c-form-control">
<option value="" ?selected=${this.instance?.rsaKey === undefined}>
<option value="" ?selected=${this.instance?.signingKey === undefined}>
---------
</option>
${until(
@ -188,7 +188,7 @@ ${this.instance?.redirectUris}</textarea
})
.then((keys) => {
return keys.results.map((key) => {
let selected = this.instance?.rsaKey === key.pk;
let selected = this.instance?.signingKey === key.pk;
if (keys.results.length === 1) {
selected = true;
}
@ -203,9 +203,7 @@ ${this.instance?.redirectUris}</textarea
html`<option>${t`Loading...`}</option>`,
)}
</select>
<p class="pf-c-form__helper-text">
${t`Key used to sign the tokens. Only required when JWT Algorithm is set to RS256.`}
</p>
<p class="pf-c-form__helper-text">${t`Key used to sign the tokens.`}</p>
</ak-form-element-horizontal>
</div>
</ak-form-group>
@ -252,29 +250,6 @@ ${this.instance?.redirectUris}</textarea
${t`(Format: hours=-1;minutes=-2;seconds=-3).`}
</p>
</ak-form-element-horizontal>
<ak-form-element-horizontal
label=${t`JWT Algorithm`}
?required=${true}
name="jwtAlg"
>
<select class="pf-c-form-control">
<option
value=${JwtAlgEnum.Rs256}
?selected=${this.instance?.jwtAlg === JwtAlgEnum.Rs256}
>
${t`RS256 (Asymmetric Encryption)`}
</option>
<option
value=${JwtAlgEnum.Hs256}
?selected=${this.instance?.jwtAlg === JwtAlgEnum.Hs256}
>
${t`HS256 (Symmetric Encryption)`}
</option>
</select>
<p class="pf-c-form__helper-text">
${t`Algorithm used to sign the JWT Tokens.`}
</p>
</ak-form-element-horizontal>
<ak-form-element-horizontal label=${t`Scopes`} name="propertyMappings">
<select class="pf-c-form-control" multiple>
${until(

View File

@ -20,7 +20,6 @@ The following placeholders will be used:
Create an OAuth2/OpenID provider with the following parameters:
- Client Type: `Confidential`
- JWT Algorithm: `RS256`
- Redirect URIs: `https://guacamole.company/` (depending on your Tomcat setup, you might have to add `/guacamole/` if the application runs in a subfolder)
- Scopes: OpenID, Email and Profile

View File

@ -20,7 +20,6 @@ The following placeholders will be used:
Create an application in authentik. Create an OAuth2/OpenID provider with the following parameters:
- Client Type: `Confidential`
- JWT Algorithm: `RS256`
- Scopes: OpenID, Email and Profile
- RSA Key: Select any available key
- Redirect URIs: `https://budibase.company/api/global/auth/oidc/callback`

View File

@ -20,7 +20,6 @@ The following placeholders will be used:
Create an application in authentik. Create an OAuth2/OpenID provider with the following parameters:
- Client Type: `Confidential`
- JWT Algorithm: `RS256`
- Scopes: OpenID, Email and Profile
- RSA Key: Select any available key
- Redirect URIs: `https://grafana.company/login/generic_oauth`

View File

@ -20,7 +20,6 @@ The following placeholders will be used:
Create an OAuth2/OpenID provider with the following parameters:
- Client Type: `Confidential`
- JWT Algorithm: `RS256`
- Redirect URIs: `https://harbor.company/c/oidc/callback`
- Scopes: OpenID, Email and Profile

View File

@ -20,7 +20,6 @@ The following placeholders will be used:
Create an application in authentik. Create an OAuth2/OpenID provider with the following parameters:
- Client Type: `Confidential`
- JWT Algorithm: `RS256`
- Scopes: OpenID, Email and Profile
- RSA Key: Select any available key
- Redirect URIs: `https://hedgedoc.company/auth/oauth2/callback`

View File

@ -21,7 +21,6 @@ The following placeholders will be used:
Create an application in authentik. Create an OAuth2/OpenID provider with the following parameters:
- Client Type: `Confidential`
- JWT Algorithm: `RS256`
- Scopes: OpenID, Email and Profile
- RSA Key: Select any available key
- Redirect URIs: `https://matrix.company/_synapse/client/oidc/callback`

View File

@ -28,7 +28,6 @@ return {
Create an application in authentik. Create an _OAuth2/OpenID Provider_ with the following parameters:
- Client Type: `Public`
- JWT Algorithm: `RS256`
- Scopes: OpenID, Email, Profile and the scope you created above
- RSA Key: Select any available key
- Redirect URIs: `https://minio.company/oauth_callback`

View File

@ -20,7 +20,6 @@ The following placeholders will be used:
Create an application in authentik. Create an OAuth2/OpenID provider with the following parameters:
- Client Type: `Confidential`
- JWT Algorithm: `RS256`
- Scopes: OpenID, Email and Profile
- RSA Key: Select any available key
- Redirect URIs: `https://wekan.company/_oauth/oidc`