MCPcopy Create free account
hub / github.com/UsefulSoftwareCo/executor / decideDcrClientReuse

Function decideDcrClientReuse

packages/core/sdk/src/oauth-service.ts:1112–1189  ·  view source on GitHub ↗
(
    input: RegisterDynamicClientInput,
    issuer: string | null,
    flowRedirectUri: string | null,
  )

Source from the content-addressed store, hash-verified

1110 );
1111
1112 const decideDcrClientReuse = (
1113 input: RegisterDynamicClientInput,
1114 issuer: string | null,
1115 flowRedirectUri: string | null,
1116 ): Effect.Effect<
1117 {
1118 readonly existingSlug: OAuthClientSlug | null;
1119 readonly registrationSlug: OAuthClientSlug;
1120 },
1121 StorageFailure
1122 > =>
1123 Effect.gen(function* () {
1124 const candidates = yield* dcrCandidatesForIssuer(input.owner, issuer);
1125 const resource = input.resource ?? null;
1126 // A candidate is reusable only when the callback it registered with the
1127 // AS still matches the current flow's callback — strict servers reject an
1128 // authorize request whose redirect_uri differs from the registration
1129 // (e.g. the callback origin changed after a sandbox was recreated while
1130 // the persisted client survived). A null stored redirect is a legacy row
1131 // predating the column: treated as matching so an upgrade doesn't
1132 // re-register every client whose callback never changed. A null FLOW
1133 // redirect has nothing to compare against, so it also reuses — the only
1134 // alternative is a fresh registration, which the missing-redirectUri
1135 // guard would fail.
1136 const redirectMatches = (candidate: DcrReuseCandidate): boolean =>
1137 candidate.redirectUri === null ||
1138 flowRedirectUri === null ||
1139 candidate.redirectUri === flowRedirectUri;
1140 // A fresh registration must never take a slug an existing candidate
1141 // holds: `createClient` deletes any colliding (owner, slug) row first,
1142 // which would clobber a client that live connections still refresh
1143 // through (a redirect-mismatched client stays valid for refresh — the
1144 // token grant doesn't involve the redirect URI).
1145 const takenSlugs = new Set(candidates.map((client) => String(client.slug)));
1146 if (resource !== null) {
1147 // Prefer a candidate matching resource AND the current redirect across
1148 // ALL candidates (mirroring the resource-less branch below). Candidates
1149 // are oldest-first, so after an origin drift the oldest matching-
1150 // resource row is the STRANDED one — but the first drift recovery
1151 // already minted a client bound to the CURRENT callback, and later
1152 // reconnects must reuse that instead of registering another duplicate
1153 // each time. Known limitation: the legacy null-redirect rule in
1154 // `redirectMatches` (a legacy row with no stored redirect matches any
1155 // flow redirect) still lets such a row win over a later, exactly-
1156 // matching one; kept deliberately so upgrades don't re-register every
1157 // client whose callback never changed.
1158 const reusable = candidates.find(
1159 (client) => client.resource === resource && redirectMatches(client),
1160 );
1161 if (reusable) {
1162 return { existingSlug: reusable.slug, registrationSlug: reusable.slug };
1163 }
1164 const slug = uniqueDcrSlug(
1165 dcrClientSlug(issuer, candidates.length > 0 ? resource : null, input.slug),
1166 takenSlugs,
1167 );
1168 return {
1169 existingSlug: null,

Callers 1

registerDynamicClientFunction · 0.85

Calls 4

dcrCandidatesForIssuerFunction · 0.85
redirectMatchesFunction · 0.85
uniqueDcrSlugFunction · 0.85
dcrClientSlugFunction · 0.85

Tested by

no test coverage detected