Skip to content

Per-client overrides for token-validation policy on Remoting Client items #1484

@michaellwest

Description

@michaellwest

Problem

Config-level validation policy (<maxTokenLifetimeSeconds> on <authenticationProvider> and <requiredScopes> on <oauthBearer>) is one-size-fits-all across the deployment. Operators cannot tighten policy for a specific caller - e.g. a short-lived CI key that should never emit a 1-hour token next to a long-running automation key, or an OAuth Client that should only accept tokens carrying spe.remoting.read while another requires spe.remoting.write. Today the only workarounds are to set the global ceiling pessimistically (hurts the long-running caller) or run separate <oauthBearer> entries per scope set (doesn't scale).

Shared Secret Client and OAuth Client items already express per-caller attributes (secret / kid / impersonated user / policy / throttle / expiry). These two validation knobs are the natural next layer: they vary per caller and belong on the item.

Proposed additions

Two optional fields on the Remoting Client templates. Both are additive: they can only narrow the global bound, never widen it.

1. MaxTokenLifetimeSeconds on the Remoting Client base template

Inherited by Shared Secret Client and OAuth Client.

  • Empty / 0 means "inherit the config-level value" (current behaviour).
  • A positive value caps the token lifetime below the global ceiling. Enforcement is min(item.MaxTokenLifetimeSeconds, config.MaxTokenLifetimeSeconds) with 0 treated as "no item cap."

2. RequiredScopes on the OAuth Client template

Multi-line field, one scope per line (same shape as OAuth Client Ids).

  • Empty means "inherit the config-level <requiredScopes>" (current behaviour).
  • When populated, enforcement is the union of config + item scopes; every listed scope must be present on the incoming token.
  • Shared Secret Client does not get this field (scopes are an OAuth concept).

Security notes

  • Both overrides are strictly additive: an item cannot weaken the global policy, only strengthen it.
  • Operators should still set sensible config-level ceilings; items are a refinement layer, not a replacement.
  • RequiredScopes save-time validator should trim whitespace, reject duplicates, and warn on wildcard-like entries.

Scope

  • Two new fields on the templates (new GUIDs, migration-safe defaults).
  • Plumb values through RemotingClientProvider.ParseApiKey / ParseOAuthClient.
  • Extend SharedSecretAuthenticationProvider.ValidateToken and OAuthBearerTokenAuthenticationProvider.Validate with per-request override arguments.
  • Dispatch in RemoteScriptCall.ashx.cs passes the matched item's overrides alongside the existing SharedSecret override.
  • Integration tests:
    • Client with item-lifetime=60s rejects a token minted with exp=300s even when config ceiling is 3600s.
    • Two OAuth Clients with different RequiredScopes; wrong-scope token against each returns 401.
  • README "How config and items layer" update noting lifetime + scopes are the two knobs that can tighten per-item.

Follow-up to the layering discussion documented in README "How config and items layer."

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions