Let standard techs use profiles without sign-in; flag unshared ones

Standard technicians (TechN0/TechN1) are no longer auto-prompted for a
delegated SharePoint sign-in when selecting a profile — only admins are.
Techs operate under the profile's app (certificate) identity, so a profile
selection never forces them to authenticate.

To keep that usable, the admin profile list now shows a "No shared access"
badge on any profile that isn't certificate-configured, since standard
techs can't operate against those until an admin registers a cert.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-11 11:27:46 +02:00
parent 84b77d99f6
commit fe33960c0e
2 changed files with 21 additions and 4 deletions
+14 -4
View File
@@ -226,8 +226,8 @@
} }
// If profile selected but no credentials → show modal (cert profiles never prompt) // If profile selected but no credentials → show modal (cert profiles never prompt)
if (Session.HasProfile && !_hasCredentials && !CurrentProfileUsesCert && _credModal is not null) if (ShouldPromptForCredentials)
await _credModal.ShowAsync(); await _credModal!.ShowAsync();
} }
// True when the selected profile authenticates app-only via a stored certificate — // True when the selected profile authenticates app-only via a stored certificate —
@@ -235,6 +235,15 @@
private bool CurrentProfileUsesCert => private bool CurrentProfileUsesCert =>
Session.CurrentProfile is { } p && AppOnly.IsConfigured(p); Session.CurrentProfile is { } p && AppOnly.IsConfigured(p);
// Whether to auto-show the delegated sign-in modal. Only admins are ever asked to
// authenticate: standard technicians (TechN0/TechN1) operate under the profile's app
// (certificate) identity and must never be prompted when selecting a profile. A profile
// that isn't cert-configured is an admin setup concern, not a sign-in for the technician.
private bool ShouldPromptForCredentials =>
Session.HasProfile && !_hasCredentials && !CurrentProfileUsesCert
&& UserContext.Role == UserRole.Admin
&& _credModal is not null;
private async Task HandleOAuthCallbackAsync() private async Task HandleOAuthCallbackAsync()
{ {
var uri = new Uri(Nav.Uri); var uri = new Uri(Nav.Uri);
@@ -320,8 +329,9 @@
// operating on the old connection. // operating on the old connection.
await RefreshCredentialState(); await RefreshCredentialState();
// New profile selected and no valid credentials for it → prompt to connect. // New profile selected and no valid credentials for it → prompt to connect.
if (Session.HasProfile && !_hasCredentials && _credModal is not null) // Standard technicians are never prompted (see ShouldPromptForCredentials).
await _credModal.ShowAsync(); if (ShouldPromptForCredentials)
await _credModal!.ShowAsync();
}); });
} }
+7
View File
@@ -79,6 +79,13 @@
{ {
<span class="chip chip-green">@T["profiles.active"]</span> <span class="chip chip-green">@T["profiles.active"]</span>
} }
@if (!AppOnlyFactory.IsConfigured(p))
{
<span class="chip chip-yellow"
title="No certificate configured — standard technicians can't use this profile. Open it and run 'Register app' (or upload a certificate) to enable shared access.">
⚠ No shared access
</span>
}
<button class="btn btn-secondary btn-sm" @onclick="() => SelectProfile(p)"> <button class="btn btn-secondary btn-sm" @onclick="() => SelectProfile(p)">
@(Session.CurrentProfile?.Id == p.Id ? T["profiles.selected"] : T["profiles.select"]) @(Session.CurrentProfile?.Id == p.Id ? T["profiles.selected"] : T["profiles.select"])
</button> </button>