diff --git a/.env.example b/.env.example
index e947507e..ed12ec45 100644
--- a/.env.example
+++ b/.env.example
@@ -55,6 +55,10 @@ OIDC_SERVICE_AUTHORIZATION=https://url-of-the-authorization-endpoint-of-the-oidc
OIDC_SERVICE_TOKEN=https://url-of-the-token-endpoint-of-the-oidc-service.com/token
OIDC_SERVICE_PROFILE=https://url-of-the-profile-endpoint-of-the-oidc-service.com/userinfo
OIDC_SERVICE_SCOPE="the list of scopes space separeted like email identity"
+# Token authentication method as seen in https://openid.net/specs/openid-connect-core-1_0.html#ClientAuthentication
+# Supported values: ClientSecretBasic (default) or ClientSecretPost
+# If in doupt, leave this empty.
+OIDC_SERVICE_AUTHMETHOD=ClientSecretBasic
# on the previous list, service is the internal name of your service, you can add as many as you want.
diff --git a/back/src/Kyoo.Authentication/AuthenticationModule.cs b/back/src/Kyoo.Authentication/AuthenticationModule.cs
index 36526676..611a9eed 100644
--- a/back/src/Kyoo.Authentication/AuthenticationModule.cs
+++ b/back/src/Kyoo.Authentication/AuthenticationModule.cs
@@ -16,6 +16,7 @@
// You should have received a copy of the GNU General Public License
// along with Kyoo. If not, see .
+using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
@@ -100,6 +101,20 @@ public static class AuthenticationModule
case "logo":
acc[provider].LogoUrl = val.Value;
break;
+ case "clientauthmethod":
+ case "authmethod":
+ case "auth":
+ case "method":
+ if (!Enum.TryParse(val.Value, out AuthMethod method))
+ {
+ Log.Error(
+ "Invalid AuthMethod value: {AuthMethod}. Ignoring.",
+ val.Value
+ );
+ break;
+ }
+ acc[provider].ClientAuthMethod = method;
+ break;
default:
Log.Error("Invalid oidc config value: {Key}", key);
return acc;
diff --git a/back/src/Kyoo.Authentication/Controllers/OidcController.cs b/back/src/Kyoo.Authentication/Controllers/OidcController.cs
index d5909256..b4fbbee9 100644
--- a/back/src/Kyoo.Authentication/Controllers/OidcController.cs
+++ b/back/src/Kyoo.Authentication/Controllers/OidcController.cs
@@ -43,19 +43,27 @@ public class OidcController(
HttpClient client = clientFactory.CreateClient();
- string auth = Convert.ToBase64String(
- Encoding.UTF8.GetBytes($"{prov.ClientId}:{prov.Secret}")
- );
- client.DefaultRequestHeaders.Add("Authorization", $"Basic {auth}");
Dictionary data =
new()
{
["code"] = code,
- ["client_id"] = prov.ClientId,
- ["client_secret"] = prov.Secret,
["redirect_uri"] = $"{options.PublicUrl.TrimEnd('/')}/api/auth/logged/{provider}",
["grant_type"] = "authorization_code",
};
+
+ if (prov.ClientAuthMethod == AuthMethod.ClientSecretBasic)
+ {
+ string auth = Convert.ToBase64String(
+ Encoding.UTF8.GetBytes($"{prov.ClientId}:{prov.Secret}")
+ );
+ client.DefaultRequestHeaders.Add("Authorization", $"Basic {auth}");
+ }
+ else if (prov.ClientAuthMethod == AuthMethod.ClientSecretPost)
+ {
+ data["client_id"] = prov.ClientId;
+ data["client_secret"] = prov.Secret;
+ }
+
HttpResponseMessage resp = prov.TokenUseJsonBody
? await client.PostAsJsonAsync(prov.TokenUrl, data)
: await client.PostAsync(prov.TokenUrl, new FormUrlEncodedContent(data));
diff --git a/back/src/Kyoo.Authentication/Models/Options/PermissionOption.cs b/back/src/Kyoo.Authentication/Models/Options/PermissionOption.cs
index 90b8cb67..458003e3 100644
--- a/back/src/Kyoo.Authentication/Models/Options/PermissionOption.cs
+++ b/back/src/Kyoo.Authentication/Models/Options/PermissionOption.cs
@@ -67,6 +67,13 @@ public class PermissionOption
public Dictionary OIDC { get; set; }
}
+public enum AuthMethod
+{
+ ClientSecretBasic,
+ ClientSecretPost,
+ None,
+}
+
public class OidcProvider
{
public string DisplayName { get; set; }
@@ -79,6 +86,11 @@ public class OidcProvider
///
public bool TokenUseJsonBody { get; set; }
+ ///
+ /// The OIDC spec allows multiples ways of authorizing the client.
+ ///
+ public AuthMethod ClientAuthMethod { get; set; } = AuthMethod.ClientSecretBasic;
+
public string ProfileUrl { get; set; }
public string? Scope { get; set; }
public string ClientId { get; set; }
@@ -108,6 +120,7 @@ public class OidcProvider
ClientId = KnownProviders[provider].ClientId;
Secret = KnownProviders[provider].Secret;
TokenUseJsonBody = KnownProviders[provider].TokenUseJsonBody;
+ ClientAuthMethod = KnownProviders[provider].ClientAuthMethod;
GetProfileUrl = KnownProviders[provider].GetProfileUrl;
GetExtraHeaders = KnownProviders[provider].GetExtraHeaders;
}
@@ -144,6 +157,7 @@ public class OidcProvider
// does not seems to have scopes
Scope = null,
TokenUseJsonBody = true,
+ ClientAuthMethod = AuthMethod.ClientSecretPost,
GetProfileUrl = (profile) => $"https://simkl.com/{profile.Sub}/dashboard/",
GetExtraHeaders = (OidcProvider self) =>
new() { ["simkl-api-key"] = self.ClientId },