(
target: {
readonly owner: Owner;
readonly name: ConnectionName;
readonly integration: IntegrationSlug;
readonly template: AuthTemplateSlug;
readonly identityLabel?: string | null;
},
client: LoadedOAuthClient,
token: OAuth2TokenResponse,
/** The scope set requested at /authorize + /token (the integration's
* declared or discovered scopes) — the recorded-scope fallback when the AS
* omits `scope`. */
requestedScopes: readonly string[],
/** The owner of `client` — persisted so refresh loads it by explicit owner. */
clientOwner: Owner,
/** Regional token endpoint override to persist when the code was redeemed
* off the client's configured host; null to use the client's token URL. */
oauthTokenUrl: string | null,
)
| 1378 | // connection row with OAuth lifecycle fields + produce its tools. |
| 1379 | // ----------------------------------------------------------------------- |
| 1380 | const mintFromToken = ( |
| 1381 | target: { |
| 1382 | readonly owner: Owner; |
| 1383 | readonly name: ConnectionName; |
| 1384 | readonly integration: IntegrationSlug; |
| 1385 | readonly template: AuthTemplateSlug; |
| 1386 | readonly identityLabel?: string | null; |
| 1387 | }, |
| 1388 | client: LoadedOAuthClient, |
| 1389 | token: OAuth2TokenResponse, |
| 1390 | /** The scope set requested at /authorize + /token (the integration's |
| 1391 | * declared or discovered scopes) — the recorded-scope fallback when the AS |
| 1392 | * omits `scope`. */ |
| 1393 | requestedScopes: readonly string[], |
| 1394 | /** The owner of `client` — persisted so refresh loads it by explicit owner. */ |
| 1395 | clientOwner: Owner, |
| 1396 | /** Regional token endpoint override to persist when the code was redeemed |
| 1397 | * off the client's configured host; null to use the client's token URL. */ |
| 1398 | oauthTokenUrl: string | null, |
| 1399 | ): Effect.Effect<Connection, StorageFailure> => |
| 1400 | Effect.gen(function* () { |
| 1401 | const provider = deps.defaultWritableProvider(); |
| 1402 | if (!provider || !provider.set) { |
| 1403 | return yield* new StorageError({ |
| 1404 | message: |
| 1405 | "No default writable credential provider is registered to store the OAuth access token.", |
| 1406 | cause: undefined, |
| 1407 | }); |
| 1408 | } |
| 1409 | const itemId = accessItemId(target.owner, target.integration, target.name); |
| 1410 | yield* provider.set(ProviderItemId.make(itemId), token.access_token); |
| 1411 | |
| 1412 | let refreshItemId: string | null = null; |
| 1413 | if (token.refresh_token) { |
| 1414 | refreshItemId = refreshItemIdFor(itemId); |
| 1415 | yield* provider.set(ProviderItemId.make(refreshItemId), token.refresh_token); |
| 1416 | } |
| 1417 | |
| 1418 | const oauthScope = recordedOAuthScope(token, requestedScopes); |
| 1419 | return yield* deps.mintOAuthConnection({ |
| 1420 | owner: target.owner, |
| 1421 | name: target.name, |
| 1422 | integration: target.integration, |
| 1423 | template: target.template, |
| 1424 | identityLabel: target.identityLabel ?? null, |
| 1425 | // The OIDC account claims travel separately: they may only FILL an |
| 1426 | // empty label, never replace a user-curated one on reconnect. |
| 1427 | derivedIdentityLabel: token.idTokenIdentityLabel ?? null, |
| 1428 | provider: String(provider.key), |
| 1429 | itemId, |
| 1430 | oauthClient: OAuthClientSlug.make(client.slug), |
| 1431 | oauthClientOwner: clientOwner, |
| 1432 | refreshItemId, |
| 1433 | expiresAt: expiresAtFrom(token), |
| 1434 | // Record the granted scope the AS echoed back. Some providers, including |
| 1435 | // Microsoft, issue a refresh token for `offline_access` but omit that |
| 1436 | // non-resource scope from the token `scope` string, so preserve it when |
| 1437 | // the refresh token proves it was granted. |
no test coverage detected