Skip to content

return to options#898

Merged
BilalG1 merged 2 commits into
devfrom
sign-in-oauth-return-to
Sep 17, 2025
Merged

return to options#898
BilalG1 merged 2 commits into
devfrom
sign-in-oauth-return-to

Conversation

@BilalG1
Copy link
Copy Markdown
Collaborator

@BilalG1 BilalG1 commented Sep 15, 2025

High-level PR Summary

This PR adds an optional returnTo parameter to the signInWithOAuth function in the Stack Auth SDK. This allows developers to specify a custom redirect URL after OAuth authentication instead of always using the default OAuth callback URL. The change updates both the interface definition and the implementation to support this new optional parameter.

⏱️ Estimated Review Time: 0h 15m

💡 Review Order Suggestion
Order File Path
1 packages/template/src/lib/stack-app/apps/interfaces/client-app.ts
2 packages/template/src/lib/stack-app/apps/implementations/client-app-impl.ts

Important

Add optional returnTo parameter to signInWithOAuth for custom redirect URLs in client-app-impl.ts and update interface in client-app.ts.

  • Behavior:
    • signInWithOAuth in client-app-impl.ts now accepts an optional options parameter with returnTo for custom redirect URLs.
    • Default redirect URL is this.urls.oauthCallback if returnTo is not provided.
  • Interfaces:
    • Updated signInWithOAuth signature in client-app.ts to include optional options parameter with returnTo.

This description was created by Ellipsis for eb748cb. You can customize this summary. It will automatically update as commits are pushed.

Review by RecurseML

🔍 Review performed on 2d2a6d7..eb748cb

✨ No bugs found, your code is sparkling clean

✅ Files analyzed, no issues (2)

packages/template/src/lib/stack-app/apps/implementations/client-app-impl.ts
packages/template/src/lib/stack-app/apps/interfaces/client-app.ts

Need help? Join our Discord

Summary by CodeRabbit

  • New Features
    • signInWithOAuth now accepts an optional options parameter with returnTo, allowing apps to override the post-login redirect URL.
    • Defaults remain unchanged; if returnTo isn’t provided, the existing OAuth callback is used.
    • Backwards compatible: existing calls without options continue to work.

@vercel
Copy link
Copy Markdown

vercel Bot commented Sep 15, 2025

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

Project Deployment Preview Comments Updated (UTC)
stack-backend Ready Ready Preview Comment Sep 16, 2025 11:43am
stack-dashboard Ready Ready Preview Comment Sep 16, 2025 11:43am
stack-demo Ready Ready Preview Comment Sep 16, 2025 11:43am
stack-docs Ready Ready Preview Comment Sep 16, 2025 11:43am

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Sep 15, 2025

Walkthrough

Adds an optional options parameter with returnTo to signInWithOAuth. The implementation now passes options.returnTo to the OAuth flow when provided, otherwise defaults to the existing oauthCallback. The public interface is updated accordingly; no other behavior changes.

Changes

Cohort / File(s) Summary
Client OAuth options support
packages/template/src/lib/stack-app/apps/implementations/client-app-impl.ts, packages/template/src/lib/stack-app/apps/interfaces/client-app.ts
Extend signInWithOAuth signature to accept options?: { returnTo?: string }; implementation uses options.returnTo when present, else falls back to default OAuth callback.

Sequence Diagram(s)

sequenceDiagram
    autonumber
    participant U as User
    participant C as StackClientApp
    participant O as OAuth Service

    U->>C: signInWithOAuth(provider, { returnTo? })
    alt returnTo provided
        C->>O: initiateOAuth(provider, redirect=returnTo)
    else no returnTo
        C->>O: initiateOAuth(provider, redirect=oauthCallback)
    end
    Note over O,C: OAuth provider redirects to chosen target
Loading

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Poem

I twitch my whiskers—options anew!
A hop to OAuth, with paths to choose.
If returnTo’s set, I’ll follow through;
Else back to callback—no time to lose.
Carrot commits and redirect hues—
Ship it swift on bunny shoes.

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Title Check ✅ Passed The title "return to options" references the primary change—adding a returnTo option to signInWithOAuth—and is concise and focused on that feature. It is related to the changeset and communicates the developer’s intent, but the phrasing is terse, not sentence-cased, and could be clearer for repository history and searchability. Overall it adequately identifies the main change but would benefit from a more explicit, conventional title.
Description Check ✅ Passed The PR description includes the repository's CONTRIBUTING.md placeholder comment and a detailed autogenerated summary that explains the behavioral change (adding an optional returnTo parameter), lists the modified files, and notes the API signature update, so it satisfies the repository's minimal template and provides useful reviewer context. The content is specific and not merely a generic placeholder, meeting the "mostly complete" criterion for a small API change. Reviewers should have enough information to understand the intent and scope of the change.
Docstring Coverage ✅ Passed No functions found in the changes. Docstring coverage check skipped.
✨ Finishing touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch sign-in-oauth-return-to

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@greptile-apps greptile-apps Bot left a comment

Choose a reason for hiding this comment

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

Greptile Summary

This PR adds an optional returnTo parameter to the signInWithOAuth method in the Stack Auth client library. The change allows developers to specify a custom redirect URL where users should be sent after completing OAuth authentication, rather than always using the default OAuth callback URL.

The implementation involves two key changes:

  1. Interface Update: The ClientAppInterface now defines signInWithOAuth with an optional options parameter containing a returnTo field
  2. Implementation Update: The ClientAppImpl class now accepts this options parameter and uses options?.returnTo ?? this.urls.oauthCallback as the redirect URL, maintaining backward compatibility by falling back to the default callback URL when no custom return URL is provided

This enhancement integrates seamlessly with the existing OAuth flow infrastructure, which already supports custom redirect URLs through the redirectUrl parameter in the underlying signInWithOAuth helper function. The change maintains the existing error handling and state management while simply allowing the redirect destination to be customized.

Confidence score: 4/5

  • This PR is safe to merge with low risk as it's an additive change that maintains backward compatibility
  • Score reflects straightforward implementation with proper fallback handling, though limited test coverage visibility
  • Pay attention to the interface and implementation files to ensure the API contract is properly maintained

2 files reviewed, no comments

Edit Code Review Bot Settings | Greptile

{
provider,
redirectUrl: this.urls.oauthCallback,
redirectUrl: options?.returnTo ?? this.urls.oauthCallback,
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Consider validating the 'returnTo' URL to ensure it is a trusted, relative URL. Unchecked, an arbitrary URL could lead to an open redirect vulnerability.

Suggested change
redirectUrl: options?.returnTo ?? this.urls.oauthCallback,
redirectUrl: isRelative(options?.returnTo) ? options.returnTo : this.urls.oauthCallback,

@patched-codes
Copy link
Copy Markdown

patched-codes Bot commented Sep 15, 2025

Documentation Changes Required

Files to Update:

  1. docs/templates/sdk/objects/stack-app.mdx
  2. docs/templates/customization/page-examples/sign-in.mdx
  3. docs/templates/getting-started/example-pages.mdx
  4. docs/templates/overview.mdx

Changes Needed:

  1. Update documentation to reflect the new optional options parameter with returnTo URL in the signInWithOAuth method.
  2. Add examples showing both basic usage and usage with custom returnTo URL in all relevant code examples and method signatures.

Note:

The documentation in docs/templates/sdk/objects/stack-app.mdx is already up to date and doesn't require changes. It already includes:

  • The correct method signature (signInWithOAuth(provider, options))
  • The options parameter with returnTo property
  • The correct TypeScript type definitions
  • Example usage with the returnTo option

Please ensure these changes are reflected in the relevant documentation files, except for docs/templates/sdk/objects/stack-app.mdx which is already updated.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/template/src/lib/stack-app/apps/implementations/client-app-impl.ts (1)

1600-1617: Bug + open-redirect risk: don’t replace OAuth callback with returnTo

redirectUrl must point to the OAuth callback handler. Passing options.returnTo directly as redirectUrl breaks the callback flow and can enable open redirects if arbitrary URLs are allowed. Instead, keep redirectUrl = this.urls.oauthCallback and propagate returnTo via a safe, relative query param (or use an explicit afterCallbackRedirectUrl option if supported by the backend).

Apply this diff:

-  async signInWithOAuth(provider: ProviderType, options?: { returnTo?: string }) {
+  async signInWithOAuth(provider: ProviderType, options?: { returnTo?: string }) {
     if (typeof window === "undefined") {
       throw new Error("signInWithOAuth can currently only be called in a browser environment");
     }
 
     this._ensurePersistentTokenStore();
     const session = await this._getSession();
-    await signInWithOAuth(
+    // Always use the OAuth callback as redirect target
+    let redirectUrl = this.urls.oauthCallback;
+    if (options?.returnTo) {
+      // enforce relative returnTo to avoid open-redirects
+      if (!(await this._isTrusted(options.returnTo))) {
+        throw new Error("returnTo must be a relative URL");
+      }
+      const base = new URL(window.location.href);
+      const cb = new URL(this.urls.oauthCallback, base);
+      cb.searchParams.set("after_auth_return_to", getRelativePart(new URL(options.returnTo, base)));
+      redirectUrl = getRelativePart(cb);
+    }
+
+    await signInWithOAuth(
       this._interface,
       {
         provider,
-        redirectUrl: options?.returnTo ?? this.urls.oauthCallback,
+        redirectUrl,
         errorRedirectUrl: this.urls.error,
         providerScope: this._oauthScopesOnSignIn[provider]?.join(" "),
       },
       session,
     );
   }
🧹 Nitpick comments (3)
packages/template/src/lib/stack-app/apps/interfaces/client-app.ts (1)

41-41: Public API: add options.returnTo — document and align types

  • Please document that options.returnTo must be a relative path (security).
  • Consider using the stronger ProviderType here for parity with the implementation.

Apply this diff to align the type and add brief docs:

@@
-    signInWithOAuth(provider: string, options?: { returnTo?: string }): Promise<void>,
+    /**
+     * Starts an OAuth sign-in. If `options.returnTo` is set, the app will return to that relative path after the OAuth callback completes.
+     * Note: `returnTo` must be a relative URL (e.g., "/dashboard").
+     */
+    signInWithOAuth(provider: ProviderType, options?: { returnTo?: string }): Promise<void>,

And add at the top:

+import { ProviderType } from "@stackframe/stack-shared/dist/utils/oauth";
packages/template/src/lib/stack-app/apps/implementations/client-app-impl.ts (2)

1600-1600: Optional: extract and reuse a typed options object

Define a shared SignInWithOAuthOptions type and reuse it here and in the interface for consistency.

-  async signInWithOAuth(provider: ProviderType, options?: { returnTo?: string }) {
+  type SignInWithOAuthOptions = { returnTo?: string };
+  async signInWithOAuth(provider: ProviderType, options?: SignInWithOAuthOptions) {

1600-1617: Send explicit afterCallbackRedirectUrl from signInWithOAuth (backend already supports it)

Backend / client-interface already accept afterCallbackRedirectUrl and addNewOAuthProviderOrScope already sends it, but signInWithOAuth does not — it currently embeds return paths into the callback URL. Change signInWithOAuth to pass afterCallbackRedirectUrl to iface.getOAuthUrl instead of encoding after_auth_return_to into redirectUrl.

Files to check: packages/template/src/lib/auth.ts (signInWithOAuth / addNewOAuthProviderOrScope), packages/stack-shared/src/interface/client-interface.ts, packages/template/src/lib/stack-app/apps/implementations/client-app-impl.ts.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2d2a6d7 and eb748cb.

📒 Files selected for processing (2)
  • packages/template/src/lib/stack-app/apps/implementations/client-app-impl.ts (2 hunks)
  • packages/template/src/lib/stack-app/apps/interfaces/client-app.ts (1 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
packages/template/**

📄 CodeRabbit inference engine (AGENTS.md)

When modifying the SDK copies, make changes in packages/template (source of truth)

Files:

  • packages/template/src/lib/stack-app/apps/implementations/client-app-impl.ts
  • packages/template/src/lib/stack-app/apps/interfaces/client-app.ts
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

Prefer ES6 Map over Record when representing key–value collections

Files:

  • packages/template/src/lib/stack-app/apps/implementations/client-app-impl.ts
  • packages/template/src/lib/stack-app/apps/interfaces/client-app.ts
🧬 Code graph analysis (1)
packages/template/src/lib/stack-app/apps/implementations/client-app-impl.ts (1)
packages/stack-shared/src/utils/oauth.tsx (1)
  • ProviderType (6-6)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (9)
  • GitHub Check: docker
  • GitHub Check: build (22.x)
  • GitHub Check: restart-dev-and-test
  • GitHub Check: setup-tests
  • GitHub Check: lint_and_build (latest)
  • GitHub Check: build (22.x)
  • GitHub Check: docker
  • GitHub Check: all-good
  • GitHub Check: Security Check

@BilalG1 BilalG1 merged commit e48ffa6 into dev Sep 17, 2025
20 checks passed
@BilalG1 BilalG1 deleted the sign-in-oauth-return-to branch September 17, 2025 01:24
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.

2 participants