Add App__Domain config to derive connect redirect URI
Let deployments set a single App__Domain (e.g. sptb.example.com) instead of spelling out the full ClientConnect__RedirectUri. The SharePoint-connect callback is derived as <domain>/connect/callback; an explicit RedirectUri still wins for back-compat. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -6,6 +6,11 @@
|
||||
# Image tag to run (default: latest)
|
||||
SPTB_TAG=latest
|
||||
|
||||
# Public domain the app is reached at (e.g. sptb.example.com or https://sptb.example.com).
|
||||
# Scheme defaults to https when omitted. The SharePoint-connect redirect URI is derived
|
||||
# from this as <domain>/connect/callback — register that on each client profile's app.
|
||||
# App__Domain=sptb.example.com
|
||||
|
||||
# OIDC app sign-in (required in Production). Authority is derived from TenantId.
|
||||
Oidc__TenantId=00000000-0000-0000-0000-000000000000
|
||||
Oidc__ClientId=00000000-0000-0000-0000-000000000000
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
namespace SharepointToolbox.Web.Core.Config;
|
||||
|
||||
/// <summary>
|
||||
/// The app's public domain (e.g. <c>sptb.example.com</c> or <c>https://sptb.example.com</c>),
|
||||
/// configured via <c>App__Domain</c>. Used to derive the SharePoint-connect redirect URI when
|
||||
/// <see cref="ClientConnectOptions.RedirectUri"/> isn't set explicitly.
|
||||
/// </summary>
|
||||
public class AppDomainOptions
|
||||
{
|
||||
public string Domain { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Builds an absolute URL for <paramref name="path"/> rooted at the configured domain, or
|
||||
/// <c>null</c> when no domain is set. Defaults to <c>https</c> when the domain has no scheme,
|
||||
/// and tolerates accidental surrounding quotes / trailing slashes (docker-compose's list-form
|
||||
/// env values can embed literal quotes).
|
||||
/// </summary>
|
||||
public string? BuildUrl(string path)
|
||||
{
|
||||
var domain = Domain?.Trim().Trim('"', '\'').TrimEnd('/');
|
||||
if (string.IsNullOrEmpty(domain))
|
||||
return null;
|
||||
|
||||
if (!domain.Contains("://", StringComparison.Ordinal))
|
||||
domain = "https://" + domain;
|
||||
|
||||
return domain + "/" + path.TrimStart('/');
|
||||
}
|
||||
}
|
||||
+15
@@ -172,6 +172,21 @@ builder.Services.AddHttpClient("oauth");
|
||||
// ── ClientConnect options ─────────────────────────────────────────────────────
|
||||
builder.Services.Configure<ClientConnectOptions>(builder.Configuration.GetSection("ClientConnect"));
|
||||
|
||||
// Derive the SharePoint-connect redirect URI from the app's public domain (App__Domain)
|
||||
// when ClientConnect__RedirectUri isn't set explicitly. Lets a deployment configure a
|
||||
// single domain (e.g. sptb.example.com) instead of spelling out the full callback URL.
|
||||
// An explicit RedirectUri still wins, so existing configs are unaffected.
|
||||
var appDomain = new AppDomainOptions();
|
||||
builder.Configuration.GetSection("App").Bind(appDomain);
|
||||
builder.Services.PostConfigure<ClientConnectOptions>(opts =>
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(opts.RedirectUri) &&
|
||||
appDomain.BuildUrl("/connect/callback") is { } callback)
|
||||
{
|
||||
opts.RedirectUri = callback;
|
||||
}
|
||||
});
|
||||
|
||||
// ── App config ────────────────────────────────────────────────────────────────
|
||||
var certsFolder = Path.Combine(dataFolder, "appcerts");
|
||||
builder.Services.Configure<AppConfiguration>(opt =>
|
||||
|
||||
@@ -28,6 +28,7 @@ Set these as environment variables (or in `appsettings.json` under the `Oidc` se
|
||||
| `Oidc__TenantId` | Entra tenant GUID |
|
||||
| `Oidc__ClientId` | App registration client ID |
|
||||
| `Oidc__ClientSecret` | App registration client secret |
|
||||
| `App__Domain` | Public domain the app is reached at, e.g. `sptb.example.com` or `https://sptb.example.com` (scheme defaults to `https`). The SharePoint-connect redirect URI is derived from it. |
|
||||
| `DataFolder` | Persistent data path (default `/data`) |
|
||||
| `ASPNETCORE_ENVIRONMENT` | Must be `Production` to enable OIDC |
|
||||
|
||||
@@ -40,8 +41,8 @@ These are separate and registered on **different** Entra apps. Don't conflate th
|
||||
1. **App sign-in (OIDC).** Logging into the toolbox itself via "Sign in with Microsoft". Uses the `Oidc__*` app above. Callback path is the framework default `/signin-oidc` (not configurable here).
|
||||
→ On **this** app registration, add redirect URI `https://your-host/signin-oidc` under the **Web** platform. This app also needs the Graph permissions the audit/reporting features require: `GroupMember.Read.All`, `Group.Read.All`, `User.Read.All`.
|
||||
|
||||
2. **SharePoint connect (per-profile).** Getting a delegated SharePoint/Graph token for a client tenant. A PKCE public-client flow that uses **each connection profile's own `ClientId`/`TenantId`** — not the `Oidc__*` app. `ClientConnect__RedirectUri` is the callback for this flow.
|
||||
→ On **each client-tenant profile's** app registration, add the `ClientConnect__RedirectUri` value (e.g. `https://your-host/connect/callback`) under the **Mobile and desktop / public client** platform.
|
||||
2. **SharePoint connect (per-profile).** Getting a delegated SharePoint/Graph token for a client tenant. A PKCE public-client flow that uses **each connection profile's own `ClientId`/`TenantId`** — not the `Oidc__*` app. The callback for this flow is derived from `App__Domain` as `<domain>/connect/callback`; set `ClientConnect__RedirectUri` to override the full URL directly.
|
||||
→ On **each client-tenant profile's** app registration, add that callback value (e.g. `https://your-host/connect/callback`) under the **Mobile and desktop / public client** platform.
|
||||
|
||||
> **HTTPS note.** The sign-in app is a confidential (Web) client, so Entra requires its `/signin-oidc` redirect URI to be **HTTPS** — plain HTTP is allowed only for `http://localhost`, not a LAN host/IP. To run OIDC on a plain-HTTP LAN deployment, put the app behind an HTTPS-terminating reverse proxy: register `https://your-host/signin-oidc`, and the app honours `X-Forwarded-Proto` (see `UseForwardedHeaders`) to build the correct `https` redirect. Without a proxy, OIDC sign-in won't work over a non-localhost HTTP host — use the local email/password login instead.
|
||||
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
{
|
||||
"DataFolder": "/data",
|
||||
"App": {
|
||||
"Domain": ""
|
||||
},
|
||||
"Oidc": {
|
||||
"TenantId": "YOUR_ENTRA_TENANT_ID",
|
||||
"ClientId": "YOUR_SPTB_APP_CLIENT_ID",
|
||||
|
||||
@@ -15,6 +15,9 @@ services:
|
||||
environment:
|
||||
- ASPNETCORE_ENVIRONMENT=Production
|
||||
- DataFolder=/data
|
||||
# Public domain the app is reached at (e.g. sptb.example.com). The SharePoint-connect
|
||||
# redirect URI is derived from it as <domain>/connect/callback.
|
||||
- App__Domain=${App__Domain:-}
|
||||
# OIDC config — overrides the placeholder values baked into appsettings.json.
|
||||
# Authority is derived from TenantId in code; do NOT set an Authority key.
|
||||
# Put real values in a .env file beside this compose file (NO quotes around
|
||||
|
||||
@@ -12,6 +12,10 @@ services:
|
||||
environment:
|
||||
- ASPNETCORE_ENVIRONMENT=Production
|
||||
- DataFolder=/data
|
||||
# Public domain the app is reached at (e.g. sptb.example.com). The SharePoint-connect
|
||||
# redirect URI (<domain>/connect/callback) is derived from it. Set your OIDC values
|
||||
# here too, or pass an env file.
|
||||
- App__Domain=${App__Domain:-}
|
||||
restart: unless-stopped
|
||||
healthcheck:
|
||||
# /account/login is anonymous and returns 200 (the app root now 302-redirects
|
||||
|
||||
Reference in New Issue
Block a user