diff --git a/src/App.tsx b/src/App.tsx
index 48bc69e..1ce9a7d 100644
--- a/src/App.tsx
+++ b/src/App.tsx
@@ -4,17 +4,24 @@ import { ConversationApp } from '@/components/ConversationApp'
import { OAuthCallback } from '@/components/OAuthCallback'
function App() {
- // Simple routing based on pathname
- const pathname = window.location.pathname;
- const isInferenceOAuthCallback = pathname === '/oauth/inference/callback';
- const isMcpOAuthCallback = pathname === '/oauth/mcp/callback';
-
- if (isInferenceOAuthCallback) {
- return ;
+ // Check if this is an OAuth callback based on query parameters
+ const urlParams = new URLSearchParams(window.location.search);
+ const code = urlParams.get('code');
+ const state = urlParams.get('state');
+
+ // Determine OAuth callback type from state parameter
+ let oauthType: 'inference' | 'mcp' | null = null;
+ if (code && state) {
+ // The state parameter includes the callback type
+ if (state.includes('inference:')) {
+ oauthType = 'inference';
+ } else if (state.includes('mcp:')) {
+ oauthType = 'mcp';
+ }
}
- if (isMcpOAuthCallback) {
- return ;
+ if (oauthType) {
+ return ;
}
return (
diff --git a/src/mcp/connection.ts b/src/mcp/connection.ts
index 22ec803..e00cadd 100644
--- a/src/mcp/connection.ts
+++ b/src/mcp/connection.ts
@@ -69,7 +69,7 @@ class MCPOAuthProvider implements OAuthClientProvider {
}
get redirectUrl(): string {
- return `${window.location.origin}/oauth/mcp/callback`;
+ return `${window.location.origin}${window.location.pathname}`;
}
get clientMetadata(): OAuthClientMetadata {
@@ -85,7 +85,7 @@ class MCPOAuthProvider implements OAuthClientProvider {
state(): string {
// Encode connection ID in the state parameter for callback identification
const randomPart = this.generateRandomString(8);
- return `${this.connectionId}.${randomPart}`;
+ return `mcp:${this.connectionId}.${randomPart}`;
}
// Generate a consistent key for the server based on URL
@@ -141,7 +141,7 @@ class MCPOAuthProvider implements OAuthClientProvider {
// Extract connection ID from state parameter
const state = event.data.state;
- if (!state || !state.startsWith(this.connectionId + '.')) return;
+ if (!state || !state.startsWith(`mcp:${this.connectionId}.`)) return;
window.removeEventListener('message', handleMessage);
popup.close();
diff --git a/src/providers/openrouter/oauth-provider.ts b/src/providers/openrouter/oauth-provider.ts
index abbfb3f..15f8623 100644
--- a/src/providers/openrouter/oauth-provider.ts
+++ b/src/providers/openrouter/oauth-provider.ts
@@ -33,7 +33,7 @@ export class OpenRouterOAuthProvider extends InferenceProvider {
constructor(config?: OpenRouterOAuthConfig) {
super();
this.oauthConfig = {
- redirectUri: `${window.location.origin}/oauth/inference/callback`,
+ redirectUri: `${window.location.origin}${window.location.pathname}`,
...config,
};
this.client = new OpenRouterClient(config || {});
@@ -253,7 +253,11 @@ export class OpenRouterOAuthProvider extends InferenceProvider {
}
const storedState: OAuthState = JSON.parse(storedStateJson);
- if (storedState.state !== state || Date.now() > storedState.expiresAt) {
+ // Extract the actual state without the prefix for comparison
+ const stateWithoutPrefix = state.replace(/^inference:/, '');
+ const storedStateWithoutPrefix = storedState.state.replace(/^inference:/, '');
+
+ if (storedStateWithoutPrefix !== stateWithoutPrefix || Date.now() > storedState.expiresAt) {
localStorage.removeItem('openrouter_oauth_state');
throw new Error('Invalid or expired OAuth state');
}
@@ -319,7 +323,9 @@ export class OpenRouterOAuthProvider extends InferenceProvider {
private generateState(): string {
const array = new Uint8Array(16);
crypto.getRandomValues(array);
- return btoa(String.fromCharCode.apply(null, Array.from(array)));
+ const randomPart = btoa(String.fromCharCode.apply(null, Array.from(array)));
+ // Include callback type in state for routing
+ return `inference:${randomPart}`;
}
private storeTokens(): void {
diff --git a/vite.config.ts b/vite.config.ts
index 2d42021..f4734f6 100644
--- a/vite.config.ts
+++ b/vite.config.ts
@@ -5,6 +5,9 @@ import path from 'path'
// https://vitejs.dev/config/
export default defineConfig({
plugins: [react()],
+ // Set base to '/' for local testing, or to your repo name for GitHub Pages
+ // e.g., base: '/example-remote-client/' for https://username.github.io/example-remote-client/
+ base: '/',
resolve: {
alias: {
'@': path.resolve(__dirname, './src'),