Regenerate the secret

This commit is contained in:
Paul Schneider 2026-06-19 01:36:08 +01:00
commit 19cf073677
10 changed files with 199 additions and 16 deletions

View file

@ -66,5 +66,6 @@
</div>
<p>
<a asp-action="Edit" asp-route-id="@Model.Id">@Localizer["Edit"]</a> |
<a asp-action="RegenerateSecret" asp-route-id="@Model.Id">@Localizer["Regenerate secret"]</a> |
<a asp-action="Index">@Localizer["Back to List"]</a>
</p>

View file

@ -0,0 +1,39 @@
@model Client
<h2>@Localizer["Regenerate client secret"]</h2>
<div class="alert alert-warning" role="alert">
<strong>@Localizer["Warning."]</strong>
@Localizer["Regenerating the secret will immediately invalidate the current one. Any client using the existing secret will be unable to authenticate until it is updated with the new value. The new secret will be displayed exactly once and cannot be recovered afterwards."]
</div>
<div>
<h4>@Model.ClientName</h4>
<hr />
<dl class="dl-horizontal">
<dt>@Html.DisplayNameFor(model => model.ClientId)</dt>
<dd>@Html.DisplayFor(model => model.ClientId)</dd>
<dt>@Localizer["Current secrets"]</dt>
<dd>
@if (Model.ClientSecrets != null && Model.ClientSecrets.Count > 0)
{
<ul>
@foreach (var secret in Model.ClientSecrets)
{
<li>@secret.Description <small class="text-muted">(created @secret.Created.ToString("u"))</small></li>
}
</ul>
}
else
{
<em>@Localizer["No secret currently set."]</em>
}
</dd>
</dl>
</div>
<form asp-action="RegenerateSecret" asp-route-id="@Model.Id" method="post">
@Html.AntiForgeryToken()
<button type="submit" class="btn btn-danger">@Localizer["Regenerate now"]</button>
<a asp-action="Details" asp-route-id="@Model.Id" class="btn btn-default">@Localizer["Cancel"]</a>
</form>

View file

@ -0,0 +1,53 @@
@{
var secret = ViewBag.NewClientSecret as string;
var expiresAt = ViewBag.NewClientSecretExpiresAt as string;
var clientName = ViewBag.NewClientSecretClientName as string;
var clientId = ViewBag.ClientId;
}
<h2>@Localizer["New client secret"]</h2>
<div class="alert alert-danger" role="alert">
<strong>@Localizer["This is the only time this secret will be displayed."]</strong>
@Localizer["Copy it now and store it in a safe place. After you leave this page, the value cannot be recovered — only its hash is stored on the server."]
</div>
<div>
<h4>@clientName</h4>
<hr />
<dl class="dl-horizontal">
<dt>@Localizer["Client identifier"]</dt>
<dd>@clientId</dd>
<dt>@Localizer["Expires at"]</dt>
<dd>@expiresAt</dd>
<dt>@Localizer["Secret value"]</dt>
<dd>
<pre id="newSecretValue" class="pre-scrollable" style="user-select: all;">@secret</pre>
<button type="button" class="btn btn-default" onclick="copySecret()">@Localizer["Copy"]</button>
<span id="copyFeedback" class="text-success" style="display:none;">@Localizer["Copied!"]</span>
</dd>
</dl>
</div>
<p>
<a asp-action="Details" asp-route-id="@clientId" class="btn btn-primary">@Localizer["I have saved the secret — return to client"]</a>
</p>
<script>
function copySecret() {
var text = document.getElementById('newSecretValue').innerText;
if (navigator.clipboard && navigator.clipboard.writeText) {
navigator.clipboard.writeText(text).then(function () {
var fb = document.getElementById('copyFeedback');
fb.style.display = 'inline';
setTimeout(function () { fb.style.display = 'none'; }, 2000);
});
} else {
// Fallback for browsers without clipboard API
var range = document.createRange();
range.selectNode(document.getElementById('newSecretValue'));
window.getSelection().removeAllRanges();
window.getSelection().addRange(range);
}
}
</script>