Skip to content

Re-wire auth to use a provider pattern. Lots of tests remove cloud references#3230

Merged
GiantRobots merged 11 commits intomainfrom
FixAuthWeirdNessCookieVersion
Mar 25, 2026
Merged

Re-wire auth to use a provider pattern. Lots of tests remove cloud references#3230
GiantRobots merged 11 commits intomainfrom
FixAuthWeirdNessCookieVersion

Conversation

@GiantRobots
Copy link
Collaborator

@GiantRobots GiantRobots commented Mar 18, 2026

Description

This PR updates the auth code in request-from-api to use dependency injection and middleware instead of the current if based approach for injecting different authentication strategies for other providers specifically temporal cloud.

This allows auth to be swapped wholesale without implementation leakage around the project and consolidating request/response wrappers also ensuring a single implementation is being used throughout (there were previously some edge cases where two sets of authnz code would be executed)

@GiantRobots GiantRobots requested review from a team, Alex-Tideman and rossedfort as code owners March 18, 2026 16:44
@vercel
Copy link

vercel bot commented Mar 18, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
holocene Ready Ready Preview, Comment Mar 23, 2026 10:04pm

Request Review

settings,
accessToken,
});

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • ⚠️ Argument of type 'EventAttribute | IFailure | PotentiallyDecodable' is not assignable to parameter of type 'Optional<WorkflowEvent | EventAttribute | PotentiallyDecodable>'.

accessToken,
});

const decodedAttributes = decodeAttributes(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • ⚠️ Argument of type 'EventAttribute | IFailure | PotentiallyDecodable' is not assignable to parameter of type 'Optional<WorkflowEvent | EventAttribute | PotentiallyDecodable>'.

settings,
accessToken,
);

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • ⚠️ Object is possibly 'null' or 'undefined'.
  • ⚠️ Object is possibly 'null' or 'undefined'.

accessToken,
);

expect(decodedHeartbeatDetails[0].heartbeatDetails.payloads[0]).toBe(2);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • ⚠️ Object is possibly 'null' or 'undefined'.
  • ⚠️ Object is possibly 'null' or 'undefined'.

headers['Authorization-Extras'] = accessTokenExtras;
const accessToken = await getAccessToken();
const idToken = await getIdToken();
if (accessToken) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • ⚠️ Element implicitly has an 'any' type because expression of type '"Authorization"' can't be used to index type '{ 'Content-Type': string; 'X-Namespace': string; }'.

if (accessToken) {
headers['Authorization'] = `Bearer ${accessToken}`;
}
if (idToken) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • ⚠️ Element implicitly has an 'any' type because expression of type '"Authorization-Extras"' can't be used to index type '{ 'Content-Type': string; 'X-Namespace': string; }'.

@temporal-cicd
Copy link
Contributor

temporal-cicd bot commented Mar 18, 2026

Warnings
⚠️

📊 Strict Mode: 114 errors in 19 files (10.6% of 1080 total)

src/lib/services/data-encoder.ts (2)
  • L46:8: Element implicitly has an 'any' type because expression of type '"Authorization"' can't be used to index type '{ 'Content-Type': string; 'X-Namespace': string; }'.
  • L49:8: Element implicitly has an 'any' type because expression of type '"Authorization-Extras"' can't be used to index type '{ 'Content-Type': string; 'X-Namespace': string; }'.
src/lib/utilities/request-from-api.ts (1)
  • L65:3: Function lacks ending return statement and return type does not include 'undefined'.
src/lib/utilities/decode-payload.ts (29)
  • L78:36: Argument of type '{ [k: string]: string; } | undefined' is not assignable to parameter of type 'Record<string, unknown>'.
  • L91:36: Argument of type '{ [k: string]: string; } | undefined' is not assignable to parameter of type 'Record<string, unknown>'.
  • L116:19: No overload matches this call.
  • L117:6: 'searchAttributes' is of type 'unknown'.
  • L117:44: Argument of type 'unknown' is not assignable to parameter of type 'Payload'.
  • L123:19: No overload matches this call.
  • L124:6: 'searchAttributes' is of type 'unknown'.
  • L124:44: Argument of type 'unknown' is not assignable to parameter of type 'Payload'.
  • L132:19: No overload matches this call.
  • L133:6: 'memo' is of type 'unknown'.
  • L133:32: Argument of type 'unknown' is not assignable to parameter of type 'Payload'.
  • L141:19: No overload matches this call.
  • L142:6: 'header' is of type 'unknown'.
  • L142:34: Argument of type 'unknown' is not assignable to parameter of type 'Payload'.
  • L151:19: No overload matches this call.
  • L152:6: 'queryResult' is of type 'unknown'.
  • L152:39: Argument of type 'unknown' is not assignable to parameter of type 'Payload'.
  • L172:22: Argument of type 'unknown' is not assignable to parameter of type 'Payload'.
  • L175:47: Argument of type 'unknown' is not assignable to parameter of type 'Payload'.
  • L224:57: Element implicitly has an 'any' type because expression of type 'string' can't be used to index type 'IUserMetadata | IWorkflowExecutionStartedEventAttributes | IWorkflowExecutionCompletedEventAttributes | ... 59 more ... | Record<...>'.
  • L225:29: Element implicitly has an 'any' type because expression of type 'string' can't be used to index type 'IUserMetadata | IWorkflowExecutionStartedEventAttributes | IWorkflowExecutionCompletedEventAttributes | ... 59 more ... | Record<...>'.
  • L227:8: Element implicitly has an 'any' type because expression of type 'string' can't be used to index type 'IUserMetadata | IWorkflowExecutionStartedEventAttributes | IWorkflowExecutionCompletedEventAttributes | ... 59 more ... | Record<...>'.
  • L231:21: Element implicitly has an 'any' type because expression of type 'string' can't be used to index type 'IUserMetadata | IWorkflowExecutionStartedEventAttributes | IWorkflowExecutionCompletedEventAttributes | ... 59 more ... | Record<...>'.
  • L233:10: Element implicitly has an 'any' type because expression of type 'string' can't be used to index type 'IUserMetadata | IWorkflowExecutionStartedEventAttributes | IWorkflowExecutionCompletedEventAttributes | ... 59 more ... | Record<...>'.
  • L284:57: Element implicitly has an 'any' type because expression of type 'string' can't be used to index type '{ id: string; attributes: EventAttribute; timestamp: string; classification: "Scheduled" | "Unspecified" | "Open" | "New" | "Started" | "Initiated" | "Running" | ... 7 more ... | "CancelRequested"; ... 69 more ...; eventId: string; } | ... 62 more ... | { ...; }'.
  • L285:29: Element implicitly has an 'any' type because expression of type 'string' can't be used to index type '{ id: string; attributes: EventAttribute; timestamp: string; classification: "Scheduled" | "Unspecified" | "Open" | "New" | "Started" | "Initiated" | "Running" | ... 7 more ... | "CancelRequested"; ... 69 more ...; eventId: string; } | ... 62 more ... | { ...; }'.
  • L287:8: Element implicitly has an 'any' type because expression of type 'string' can't be used to index type '{ id: string; attributes: EventAttribute; timestamp: string; classification: "Scheduled" | "Unspecified" | "Open" | "New" | "Started" | "Initiated" | "Running" | ... 7 more ... | "CancelRequested"; ... 69 more ...; eventId: string; } | ... 62 more ... | { ...; }'.
  • L289:21: Element implicitly has an 'any' type because expression of type 'string' can't be used to index type '{ id: string; attributes: EventAttribute; timestamp: string; classification: "Scheduled" | "Unspecified" | "Open" | "New" | "Started" | "Initiated" | "Running" | ... 7 more ... | "CancelRequested"; ... 69 more ...; eventId: string; } | ... 62 more ... | { ...; }'.
  • L291:10: Element implicitly has an 'any' type because expression of type 'string' can't be used to index type '{ id: string; attributes: EventAttribute; timestamp: string; classification: "Scheduled" | "Unspecified" | "Open" | "New" | "Started" | "Initiated" | "Running" | ... 7 more ... | "CancelRequested"; ... 69 more ...; eventId: string; } | ... 62 more ... | { ...; }'.
src/lib/models/event-history/index.ts (6)
  • L42:45: Argument of type 'EventAttribute | IFailure | PotentiallyDecodable' is not assignable to parameter of type 'Optional<WorkflowEvent | EventAttribute | PotentiallyDecodable>'.
  • L131:9: The operand of a 'delete' operator must be optional.
  • L132:9: The operand of a 'delete' operator must be optional.
  • L133:9: The operand of a 'delete' operator must be optional.
  • L134:9: The operand of a 'delete' operator must be optional.
  • L135:9: The operand of a 'delete' operator must be optional.
src/lib/models/event-history/get-event-attributes.test.ts (1)
  • L187:13: Element implicitly has an 'any' type because expression of type 'string' can't be used to index type 'WorkflowEvent'.
src/lib/models/event-history/to-event-history.test.ts (2)
  • L187:13: Element implicitly has an 'any' type because expression of type 'string' can't be used to index type 'WorkflowEvent'.
  • L211:13: Element implicitly has an 'any' type because expression of type 'string' can't be used to index type 'HistoryEvent'.
src/lib/models/pending-activities/index.ts (1)
  • L30:4: Argument of type 'EventAttribute | IFailure | PotentiallyDecodable' is not assignable to parameter of type 'Optional<WorkflowEvent | EventAttribute | PotentiallyDecodable>'.
src/lib/models/pending-activities/to-decoded-pending-activities.test.ts (4)
  • L22:11: Object is possibly 'null' or 'undefined'.
  • L22:11: Object is possibly 'null' or 'undefined'.
  • L23:11: Object is possibly 'null' or 'undefined'.
  • L23:11: Object is possibly 'null' or 'undefined'.
src/lib/services/query-service.ts (3)
  • L99:8: 'e' is of type 'unknown'.
  • L100:54: 'e' is of type 'unknown'.
  • L109:8: Type 'unknown' is not assignable to type 'Error | undefined'.
src/lib/services/workflow-service.ts (23)
  • L195:6: Type 'ErrorCallback' is not assignable to type '(error: unknown, toasts?: Toaster, errors?: Writable<NetworkError | null>, isBrowser?: boolean) => void'.
  • L257:4: Type 'ErrorCallback' is not assignable to type '(error: unknown, toasts?: Toaster, errors?: Writable<NetworkError | null>, isBrowser?: boolean) => void'.
  • L296:45: Argument of type 'unknown' is not assignable to parameter of type 'WorkflowExecutionAPIResponse | undefined'.
  • L429:28: No overload matches this call.
  • L645:4: Type 'ErrorCallback' is not assignable to type '(error: unknown, toasts?: Toaster, errors?: Writable<NetworkError | null>, isBrowser?: boolean) => void'.
  • L646:10: Argument of type '(response?: WorkflowExecutionAPIResponse) => WorkflowExecution' is not assignable to parameter of type '(value: unknown) => WorkflowExecution | PromiseLike'.
  • L676:4: Element implicitly has an 'any' type because expression of type 'string' can't be used to index type 'ISearchAttributes'.
  • L752:37: Argument of type 'SearchAttributeInput[]' is not assignable to parameter of type '{ type: "Unspecified" | "Keyword" | "Text" | "Int" | "Double" | "Bool" | "KeywordList" | "Datetime"; label: string; value?: any; }[]'.
  • L815:8: Type 'ErrorCallback' is not assignable to type '(error: unknown, toasts?: Toaster, errors?: Writable<NetworkError | null>, isBrowser?: boolean) => void'.
  • L839:8: 'workflow' is possibly 'undefined'.
  • L841:8: 'workflow' is possibly 'undefined'.
  • L849:8: 'workflow' is possibly 'undefined'.
  • L851:8: 'workflow' is possibly 'undefined'.
  • L858:28: Element implicitly has an 'any' type because expression of type '0' can't be used to index type '{}'.
  • L863:8: Element implicitly has an 'any' type because expression of type '0' can't be used to index type '{}'.
  • L865:10: Element implicitly has an 'any' type because expression of type '0' can't be used to index type '{}'.
  • L868:8: Element implicitly has an 'any' type because expression of type '0' can't be used to index type '{}'.
  • L1015:20: Argument of type 'WorkflowExecution | undefined' is not assignable to parameter of type 'WorkflowExecution'.
  • L1054:28: Argument of type 'string | undefined' is not assignable to parameter of type 'string'.
  • L1082:10: Property 'executions' does not exist on type 'WithoutNextPageToken'.
  • L1082:41: Argument of type '(token: string) => Promise' is not assignable to parameter of type '(token?: NextPageToken | undefined) => Promise'.
  • L1126:6: Type 'ErrorCallback' is not assignable to type '(error: unknown, toasts?: Toaster, errors?: Writable<NetworkError | null>, isBrowser?: boolean) => void'.
  • L1155:6: Type 'ErrorCallback' is not assignable to type '(error: unknown, toasts?: Toaster, errors?: Writable<NetworkError | null>, isBrowser?: boolean) => void'.
src/lib/svelte-mocks/app/state.ts (1)
  • L5:4: Type 'null' is not assignable to type 'string[]'.
src/lib/utilities/decode-local-activity.ts (2)
  • L71:6: Argument of type 'WorkflowEvent | EventAttribute | IMemo | PotentiallyDecodable' is not assignable to parameter of type 'Optional<WorkflowEvent | EventAttribute | PotentiallyDecodable>'.
  • L76:41: Argument of type 'Payload | undefined' is not assignable to parameter of type 'Payload'.
src/lib/utilities/export-history.ts (3)
  • L49:35: Argument of type 'WorkflowEvent | EventAttribute | IMemo | PotentiallyDecodable' is not assignable to parameter of type 'Optional<WorkflowEvent | EventAttribute | PotentiallyDecodable>'.
  • L60:50: Argument of type 'null' is not assignable to parameter of type '((key: string, value: { events: HistoryEvent[]; }) => { events: HistoryEvent[]; }) | undefined'.
  • L101:15: Argument of type 'Replace<Optional<WorkflowEvent | EventAttribute | PotentiallyDecodable>, Optional<WorkflowEvent | EventAttribute | PotentiallyDecodable>>[]' is not assignable to parameter of type 'HistoryEvent[]'.
src/lib/components/event/payload-decoder.svelte (5)
  • L28:26: Element implicitly has an 'any' type because expression of type 'string' can't be used to index type 'WorkflowEvent | IUserMetadata | IWorkflowExecutionStartedEventAttributes | IWorkflowExecutionCompletedEventAttributes | ... 59 more ... | Record<...>'.
  • L28:41: Element implicitly has an 'any' type because expression of type 'string' can't be used to index type 'WorkflowEvent | IUserMetadata | IWorkflowExecutionStartedEventAttributes | IWorkflowExecutionCompletedEventAttributes | ... 59 more ... | Record<...>'.
  • L54:8: Argument of type 'WorkflowEvent | EventAttribute | IMemo | PotentiallyDecodable' is not assignable to parameter of type 'Optional<WorkflowEvent | EventAttribute | PotentiallyDecodable>'.
  • L56:31: Element implicitly has an 'any' type because expression of type 'string' can't be used to index type '{}'.
  • L57:35: Element implicitly has an 'any' type because expression of type 'string' can't be used to index type '{}'.
src/lib/components/event/event-summary-row.svelte (5)
  • L130:6: Argument of type 'string | undefined' is not assignable to parameter of type 'string'.
  • L167:23: Parameter 'event' implicitly has an 'any' type.
  • L179:30: Parameter 'group' implicitly has an 'any' type.
  • L179:37: Parameter 'hoveredEventId' implicitly has an 'any' type.
  • L310:16: Type 'ITimestamp | null | undefined' is not assignable to type 'ITimestamp'.
src/lib/components/lines-and-dots/svg/timeline-graph-row.svelte (7)
  • L98:20: 'distance' is possibly 'null'.
  • L98:31: 'workflowDistance' is possibly 'null'.
  • L109:20: 'distance' is possibly 'null'.
  • L109:31: 'workflowDistance' is possibly 'null'.
  • L149:29: 'activityTaskScheduled.attributes.attempt' is possibly 'null' or 'undefined'.
  • L242:12: 'pendingActivity.attempt' is possibly 'null' or 'undefined'.
  • L285:13: 'activityTaskScheduled' is possibly 'undefined'.
src/lib/layouts/workflow-run-layout.svelte (7)
  • L102:39: Type 'string | undefined' is not assignable to type 'string'.
  • L152:6: Type 'WorkflowExecution | undefined' is not assignable to type 'WorkflowExecution | null'.
  • L166:4: Type 'undefined' is not assignable to type 'NetworkError | null'.
  • L169:18: No overload matches this call.
  • L178:28: Parameter 'fullHistory' implicitly has an 'any' type.
  • L178:41: Parameter 'pause' implicitly has an 'any' type.
  • L210:35: Argument of type 'null' is not assignable to parameter of type '((key: string, value: { eventHistory: WorkflowEvents; workflow: WorkflowExecution | null; workers: IDescribeTaskQueueResponse; workersLoaded: boolean; metadata: WorkflowMetadata | null; userMetadata: { ...; }; }) => { ...; }) | undefined'.
src/lib/pages/workflow-call-stack.svelte (3)
  • L28:8: Type 'WorkflowExecution | null' is not assignable to type 'Eventual<{ id: string; runId: string; }>'.
  • L42:30: 'workers.pollers.length' is possibly 'undefined'.
  • L96:12: Type 'string | undefined' is not assignable to type 'string | number'.
src/lib/pages/workflow-query.svelte (9)
  • L49:5: Type 'string | undefined' is not assignable to type 'string'.
  • L58:32: 'a.name' is possibly 'undefined'.
  • L59:32: 'b.name' is possibly 'undefined'.
  • L64:13: 'a.name' is possibly 'undefined'.
  • L64:34: No overload matches this call.
  • L100:6: Type 'Promise | Promise<IPayload[]>' is not assignable to type 'Promise'.
  • L118:8: Type '{ payloads: IPayloads; } | null' is not assignable to type 'IPayloads | undefined'.
  • L162:12: Type '"retry" | null' is not assignable to type '"action" | "activity" | "add-square" | "add" | "apple" | "archives" | "arrow-down" | "arrow-left" | "arrow-up" | "arrow-right" | "ascending" | "astronaut" | "batch-operation" | ... 134 more ... | undefined'.
  • L190:12: Type 'false | "opacity-50"' is not assignable to type 'string | undefined'.

Generated by 🚫 dangerJS against 8376b0b

settings,
$authUser.accessToken,
);
const decodedAttributes = decodePayloadAttributes(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • ⚠️ Argument of type 'WorkflowEvent | EventAttribute | IMemo | PotentiallyDecodable' is not assignable to parameter of type 'Optional<WorkflowEvent | EventAttribute | PotentiallyDecodable>'.

…Re-wire with-access-token to use pre/post hooks so code paths can be determined by the caller. Lots of tests
@GiantRobots GiantRobots changed the title Fix auth weird ness cookie version Re-wire auth to use a provider pattern. Lots of tests remove cloud references Mar 20, 2026

const settings: Settings = {
auth: {
enabled: false,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • ⚠️ Type 'null' is not assignable to type 'string[]'.

Copy link
Contributor

@andrewzamojc andrewzamojc left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code looks good. The new way makes sense and cleans up the calling code nicely. Tons of tests 👍 I can manually test next.

}

export async function getAccessToken(): Promise<string> {
if (!BROWSER || !provider) return '';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

silent, but seems fine.

): Promise<string> {
const settings = page.data?.settings;
return getCodecEndpoint(settings);
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

wizardry...

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is approximately how we do it now. I very much dislike how we use a store and push it down by setting it in the page it's VERY VERY side effecty so this is step1 in changing it.

let response = await executeRequest(context);

if (isBrowser) {
response = await runPostResponse(response, {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Dope

Copy link
Collaborator

@rossnelson rossnelson left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM! I tested using the local oidc server and all looks good.

Side Note: I've got a follow-up draft PR (#3248) that adds redirect-to-login when refreshTokens returns false in ossPostResponse — that behavior was missing for requests that bypass handleError (e.g. background workflow count polls).

@GiantRobots GiantRobots merged commit 92cd681 into main Mar 25, 2026
25 checks passed
@GiantRobots GiantRobots deleted the FixAuthWeirdNessCookieVersion branch March 25, 2026 00:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants