feat: initial Jellyfin OIDC auth plugin
OpenID Connect SSO for Jellyfin 10.10 (net8.0). Authorization code flow with PKCE via IdentityModel.OidcClient, automatic user creation with random password, role based admin/access mapping, plugin repo manifest. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
120
Jellyfin.Plugin.OidcAuth/Configuration/configPage.html
Normal file
120
Jellyfin.Plugin.OidcAuth/Configuration/configPage.html
Normal file
@@ -0,0 +1,120 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>OIDC Auth</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="OidcAuthConfigPage" data-role="page" class="page type-interior pluginConfigurationPage" data-require="emby-input,emby-button,emby-checkbox">
|
||||
<div data-role="content">
|
||||
<div class="content-primary">
|
||||
<form id="OidcAuthConfigForm">
|
||||
<div class="verticalSection verticalSection-extrabottompadding">
|
||||
<div class="sectionTitleContainer flex align-items-center">
|
||||
<h2 class="sectionTitle">OIDC Auth</h2>
|
||||
</div>
|
||||
|
||||
<div class="inputContainer">
|
||||
<input is="emby-input" id="OidIssuer" type="url" label="Issuer URL" />
|
||||
<div class="fieldDescription">Base URL of your OIDC provider, e.g. https://auth.example.com. The discovery document is loaded from <issuer>/.well-known/openid-configuration.</div>
|
||||
</div>
|
||||
|
||||
<div class="inputContainer">
|
||||
<input is="emby-input" id="OidClientId" type="text" label="Client ID" />
|
||||
</div>
|
||||
|
||||
<div class="inputContainer">
|
||||
<input is="emby-input" id="OidClientSecret" type="password" label="Client Secret" autocomplete="new-password" />
|
||||
</div>
|
||||
|
||||
<div class="inputContainer">
|
||||
<input is="emby-input" id="OidScopes" type="text" label="Scopes" />
|
||||
<div class="fieldDescription">Space separated. Default: openid profile email. Add e.g. "groups" if your provider needs it for the role claim.</div>
|
||||
</div>
|
||||
|
||||
<div class="inputContainer">
|
||||
<input is="emby-input" id="UsernameClaim" type="text" label="Username claim" />
|
||||
<div class="fieldDescription">Claim used as Jellyfin username. Default: preferred_username. Falls back to "sub".</div>
|
||||
</div>
|
||||
|
||||
<div class="inputContainer">
|
||||
<input is="emby-input" id="RoleClaim" type="text" label="Role claim" />
|
||||
<div class="fieldDescription">Claim containing groups/roles. Default: groups.</div>
|
||||
</div>
|
||||
|
||||
<div class="inputContainer">
|
||||
<input is="emby-input" id="AllowedRoles" type="text" label="Allowed roles" />
|
||||
<div class="fieldDescription">Comma separated. Only users with one of these roles may log in. Empty = everyone.</div>
|
||||
</div>
|
||||
|
||||
<div class="inputContainer">
|
||||
<input is="emby-input" id="AdminRoles" type="text" label="Admin roles" />
|
||||
<div class="fieldDescription">Comma separated. Users with one of these roles become Jellyfin administrators. Empty = never touch admin flag.</div>
|
||||
</div>
|
||||
|
||||
<div class="checkboxContainer checkboxContainer-withDescription">
|
||||
<label class="emby-checkbox-label">
|
||||
<input is="emby-checkbox" id="CreateUsersIfMissing" type="checkbox" />
|
||||
<span>Create users on first login</span>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="checkboxContainer checkboxContainer-withDescription">
|
||||
<label class="emby-checkbox-label">
|
||||
<input is="emby-checkbox" id="SetRandomPasswordOnCreate" type="checkbox" />
|
||||
<span>Set random password for auto-created users (recommended — without it, anyone can log in as them with a blank password)</span>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="checkboxContainer checkboxContainer-withDescription">
|
||||
<label class="emby-checkbox-label">
|
||||
<input is="emby-checkbox" id="DisableEndpointValidation" type="checkbox" />
|
||||
<span>Disable strict endpoint validation (needed for Google and other providers whose endpoints are on a different host than the issuer)</span>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<button is="emby-button" type="submit" class="raised button-submit block emby-button">
|
||||
<span>Save</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="fieldDescription" style="margin-top: 1em;">
|
||||
Login URL: <code><your jellyfin address>/OidcAuth/login</code> —
|
||||
register <code><your jellyfin address>/OidcAuth/callback</code> as redirect URI at your provider.
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<script type="text/javascript">
|
||||
(function () {
|
||||
var pluginId = '96badb44-9940-4ff0-befc-5f987159152c';
|
||||
var textFields = ['OidIssuer', 'OidClientId', 'OidClientSecret', 'OidScopes', 'UsernameClaim', 'RoleClaim', 'AllowedRoles', 'AdminRoles'];
|
||||
var boolFields = ['CreateUsersIfMissing', 'SetRandomPasswordOnCreate', 'DisableEndpointValidation'];
|
||||
|
||||
document.querySelector('#OidcAuthConfigPage').addEventListener('pageshow', function () {
|
||||
Dashboard.showLoadingMsg();
|
||||
ApiClient.getPluginConfiguration(pluginId).then(function (config) {
|
||||
textFields.forEach(function (f) { document.querySelector('#' + f).value = config[f] || ''; });
|
||||
boolFields.forEach(function (f) { document.querySelector('#' + f).checked = !!config[f]; });
|
||||
Dashboard.hideLoadingMsg();
|
||||
});
|
||||
});
|
||||
|
||||
document.querySelector('#OidcAuthConfigForm').addEventListener('submit', function (e) {
|
||||
e.preventDefault();
|
||||
Dashboard.showLoadingMsg();
|
||||
ApiClient.getPluginConfiguration(pluginId).then(function (config) {
|
||||
textFields.forEach(function (f) { config[f] = document.querySelector('#' + f).value; });
|
||||
boolFields.forEach(function (f) { config[f] = document.querySelector('#' + f).checked; });
|
||||
ApiClient.updatePluginConfiguration(pluginId, config).then(function (result) {
|
||||
Dashboard.processPluginConfigurationUpdateResult(result);
|
||||
});
|
||||
});
|
||||
return false;
|
||||
});
|
||||
})();
|
||||
</script>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user