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>
121 lines
6.5 KiB
HTML
121 lines
6.5 KiB
HTML
<!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>
|