Skip to content

Conversation

@fry69
Copy link

@fry69 fry69 commented Oct 25, 2025

fix #32

This is a vibe coded "fix" for the Next.js example app. It required a bit of re-work, since the SDK does not seem to offer the needed OAuth functionality (currently), so I (okay OpenAI Codex) re-implemented the necessary functions according to RFCs and https://openrouter.ai/docs/use-cases/oauth-pkce in src/lib/oauth.ts

This PR also contains an updated package.json and fixes to the chat page.

Treat this as inspiration material. It is not meant as a serious fix.

It will work with these "fixes", see here:

Bildschirmfoto 2025-10-25 um 14 55 11

Some highlights from this re-implementation process (all fixed of course, but I find those very interesting insights as in common stumbling blocks):


• OAuth Flow Fails After Redirect

  • src/app/(app)/page.tsx:35 relies on the searchParams prop coming from Next’s generated PageProps. During npm run build && npm run start, that page is statically prerendered, so searchParams is resolved at build time (it’s always {} in production HTML). When OpenRouter redirects to /?code=..., hydration reuses that static HTML and our effect never sees p.code, so connectionState stays "disconnected". Because step 4 of the OpenRouter PKCE docs (exchange the returned code for a key) never runs, the stored verifier remains (openrouter_code_verifier), and the UI just keeps showing “Connect OpenRouter Account”. In dev (next dev) the page is rendered per-request, so this bug hides, but it always breaks in production builds.

  • The OpenRouter OAuth guide explicitly states that after the callback, you must “read the authorization code from the callback URL and immediately exchange it via POST https://openrouter.ai/api/v1/auth/keys”. Our code attempts this but never reads the live query string, so we violate that requirement.

Secondary Gaps vs. Docs

  • The same doc calls out generating and validating a state parameter to prevent CSRF. Our helper (createAuthorizationUrl) doesn’t set state, nor do we store/verify it on return, so even after we fix the code issue we’d still be missing that security check.

What This Means

  • Until we switch to a runtime source for the query string (e.g., useSearchParams() or reading window.location.search, or mark the page dynamic = 'force-dynamic'), the OAuth code-exchange step will never fire in production, so users can’t finish the flow even though OpenRouter issues a code.

  • We should also add optional state generation/storage/validation to comply with the official PKCE guidance.

Let me know if you’d like me to implement the runtime search-param handling (and state support) next.


• OAuth Flow Fails After Redirect

  • src/app/(app)/page.tsx:35 relies on the searchParams prop coming from Next’s generated PageProps. During npm run build && npm run start, that page is statically prerendered, so searchParams is resolved at build time (it’s always {} in production HTML). When OpenRouter redirects to /?code=..., hydration reuses that static HTML and our effect never sees p.code, so connectionState stays "disconnected". Because step 4 of the OpenRouter PKCE docs (exchange the returned code for a key) never runs, the stored verifier remains (openrouter_code_verifier), and the UI just keeps showing “Connect OpenRouter Account”. In dev (next dev) the page is rendered per-request, so this bug hides, but it always breaks in production builds.

  • The OpenRouter OAuth guide explicitly states that after the callback, you must “read the authorization code from the callback URL and immediately exchange it via POST https://openrouter.ai/api/v1/auth/keys”. Our code attempts this but never reads the live query string, so we violate that requirement.

Secondary Gaps vs. Docs

  • The same doc calls out generating and validating a state parameter to prevent CSRF. Our helper (createAuthorizationUrl) doesn’t set state, nor do we store/verify it on return, so even after we fix the code issue we’d still be missing that security check.

What This Means

  • Until we switch to a runtime source for the query string (e.g., useSearchParams() or reading window.location.search, or mark the page dynamic = 'force-dynamic'), the OAuth code-exchange step will never fire in production, so users can’t finish the flow even though OpenRouter issues a code.

  • We should also add optional state generation/storage/validation to comply with the official PKCE guidance.

Let me know if you’d like me to implement the runtime search-param handling (and state support) next.

@socket-security
Copy link

socket-security bot commented Oct 25, 2025

Review the following changes in direct dependencies. Learn more about Socket for GitHub.

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Updated@​types/​react-dom@​19.1.9 ⏵ 19.2.2100 +110075 +194100
Updated@​types/​react@​19.1.13 ⏵ 19.2.21001007995 +1100
Updated@​types/​node@​20.19.17 ⏵ 24.9.1100 +110081 +196100
Updatedtailwindcss@​4.1.13 ⏵ 4.1.16100 +110084 +198100
Updatedtypescript@​5.9.2 ⏵ 5.9.310010090 +19990
Updatedeslint@​9.36.0 ⏵ 9.38.097 +110010094100
Updated@​tailwindcss/​postcss@​4.1.13 ⏵ 4.1.16100 +1100100 +2199100

View full report

@socket-security
Copy link

socket-security bot commented Oct 25, 2025

Warning

Review the following alerts detected in dependencies.

According to your organization's Security Policy, it is recommended to resolve "Warn" alerts. Learn more about Socket for GitHub.

Action Severity Alert  (click "▶" to expand/collapse)
Warn High
[email protected] has a License Policy Violation.

License: CC-BY-4.0 (npm metadata)

License: CC-BY-4.0 (package/LICENSE)

License: CC-BY-4.0 (package/package.json)

From: examples/nextjs-example/package-lock.jsonnpm/[email protected]npm/[email protected]

ℹ Read more on: This package | This alert | What is a license policy violation?

Next steps: Take a moment to review the security alert above. Review the linked package source code to understand the potential risk. Ensure the package is not malicious before proceeding. If you're unsure how to proceed, reach out to your security team or ask the Socket team for help at [email protected].

Suggestion: Find a package that does not violate your license policy or adjust your policy to allow this package's license.

Mark the package as acceptable risk. To ignore this alert only in this pull request, reply with the comment @SocketSecurity ignore npm/[email protected]. You can also ignore all packages with @SocketSecurity ignore-all. To ignore an alert for all future pull requests, use Socket's Dashboard to change the triage state of this alert.

Warn High
[email protected] has a License Policy Violation.

License: MIT-Khronos-old (package/ThirdPartyNoticeText.txt)

License: CC-BY-4.0 (package/ThirdPartyNoticeText.txt)

License: LicenseRef-W3C-Community-Final-Specification-Agreement (package/ThirdPartyNoticeText.txt)

From: examples/nextjs-example/package-lock.jsonnpm/[email protected]

ℹ Read more on: This package | This alert | What is a license policy violation?

Next steps: Take a moment to review the security alert above. Review the linked package source code to understand the potential risk. Ensure the package is not malicious before proceeding. If you're unsure how to proceed, reach out to your security team or ask the Socket team for help at [email protected].

Suggestion: Find a package that does not violate your license policy or adjust your policy to allow this package's license.

Mark the package as acceptable risk. To ignore this alert only in this pull request, reply with the comment @SocketSecurity ignore npm/[email protected]. You can also ignore all packages with @SocketSecurity ignore-all. To ignore an alert for all future pull requests, use Socket's Dashboard to change the triage state of this alert.

View full report

@fry69
Copy link
Author

fry69 commented Oct 29, 2025

fixed see #32

@fry69 fry69 closed this Oct 29, 2025
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.

Next.js example client does not build/throws OAuth error

1 participant