Skip to main content

Overview

GitStarRecall supports two authentication methods:
  1. OAuth (Recommended) - Secure authorization flow with PKCE
  2. Personal Access Token (PAT) - Fallback for power users
OAuth is recommended for better security. Tokens are held in memory and never persisted to localStorage in raw form.
OAuth uses the PKCE (Proof Key for Code Exchange) flow to keep your GitHub credentials secure. The client secret is only used server-side during token exchange.

Step 1: Create GitHub OAuth App

1

Navigate to GitHub Developer Settings

Go to GitHub Developer Settings and click OAuth AppsNew OAuth App.
2

Configure OAuth App

Fill in the application details:
Application name: GitStarRecall (Dev)
Homepage URL: http://localhost:5173
Authorization callback URL: http://localhost:5173/auth/callback
The callback URL must match exactly. Mismatched URLs will cause OAuth exchange failures.
3

Get Client Credentials

After creating the app, you’ll see:
  • Client ID - Public identifier for your OAuth app
  • Client Secret - Click Generate a new client secret to create one
Save the client secret immediately - you won’t be able to see it again.

Step 2: Configure Environment Variables

Set up both client-side and server-side environment variables:
# Client-side OAuth configuration
VITE_GITHUB_CLIENT_ID=Iv1.a1b2c3d4e5f6g7h8
VITE_GITHUB_REDIRECT_URI=http://localhost:5173/auth/callback
VITE_GITHUB_OAUTH_EXCHANGE_URL=/api/github/oauth/exchange

# Server-side OAuth configuration (for token exchange)
GITHUB_OAUTH_CLIENT_ID=Iv1.a1b2c3d4e5f6g7h8
GITHUB_OAUTH_CLIENT_SECRET=your_client_secret_here
GITHUB_OAUTH_REDIRECT_URI=http://localhost:5173/auth/callback
Both VITE_GITHUB_REDIRECT_URI and GITHUB_OAUTH_REDIRECT_URI must be identical and match your GitHub OAuth app callback URL.

Step 3: OAuth Flow Details

The OAuth flow works as follows:
1

User Clicks 'Connect GitHub'

The app generates a PKCE code verifier and challenge:
// Generate random verifier and state
const verifier = randomString(48);
const state = randomString(32);
const challenge = base64UrlEncode(await sha256(verifier));

// Store in sessionStorage for callback verification
sessionStorage.setItem('gitstarrecall.oauth.state', state);
sessionStorage.setItem('gitstarrecall.oauth.verifier', verifier);
2

Redirect to GitHub Authorization

User is redirected to GitHub with PKCE parameters:
https://github.com/login/oauth/authorize?
  client_id=Iv1.a1b2c3d4e5f6g7h8
  &redirect_uri=http://localhost:5173/auth/callback
  &scope=read:user repo
  &state=random_state_value
  &code_challenge=challenge_hash
  &code_challenge_method=S256
  &allow_signup=false
Requested scopes:
  • read:user - Read user profile information
  • repo - Access repositories including private starred repos
3

GitHub Redirects Back with Code

After authorization, GitHub redirects to:
http://localhost:5173/auth/callback?code=abc123&state=random_state_value
4

Exchange Code for Token

The app sends the code to the backend exchange endpoint:
// Client sends to /api/github/oauth/exchange
const response = await fetch('/api/github/oauth/exchange', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    code: 'abc123',
    codeVerifier: verifier,
    redirectUri: config.redirectUri,
    clientId: config.clientId,
  }),
});
Backend exchanges with GitHub using client secret:
// Server-side exchange (api/github/oauth/exchange.js)
const ghResponse = await fetch('https://github.com/login/oauth/access_token', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    client_id: process.env.GITHUB_OAUTH_CLIENT_ID,
    client_secret: process.env.GITHUB_OAUTH_CLIENT_SECRET,
    code,
    redirect_uri: process.env.GITHUB_OAUTH_REDIRECT_URI,
    code_verifier: codeVerifier,
  }),
});
5

Token Stored in Memory

Access token is stored in React state (memory only):
// Token normalization removes common prefixes
function normalizeTokenInput(raw: string): string {
  let token = raw.trim();
  token = token.replace(/^bearer\s+/i, '');
  token = token.replace(/^token\s+/i, '');
  token = token.replace(/^['"]+|['"]+$/g, '').trim();
  return token;
}

setAccessToken(normalizeTokenInput(token));
setAuthMethod('oauth');
Tokens are never persisted to localStorage or sessionStorage. They exist only in memory and are lost on page refresh.

Vercel Deployment

For production deployment on Vercel:
1

Set Environment Variables

Add all six environment variables in Vercel project settings:
VITE_GITHUB_CLIENT_ID
VITE_GITHUB_REDIRECT_URI
VITE_GITHUB_OAUTH_EXCHANGE_URL
GITHUB_OAUTH_CLIENT_ID
GITHUB_OAUTH_CLIENT_SECRET
GITHUB_OAUTH_REDIRECT_URI
2

Verify Routing Configuration

The included vercel.json handles SPA routing:
{
  "rewrites": [
    { "source": "/api/(.*)", "destination": "/api/$1" },
    { "source": "/(.*)", "destination": "/index.html" }
  ]
}
This ensures /auth/callback refreshes work correctly.
3

Update GitHub OAuth App

Add your production callback URL to the GitHub OAuth app:
https://your-domain.vercel.app/auth/callback

Personal Access Token (PAT) Fallback

For development or self-hosted deployments, you can use a Personal Access Token instead of OAuth.

Step 1: Create GitHub PAT

1

Navigate to Token Settings

Go to GitHub Personal Access Tokens and click Generate new tokenGenerate new token (classic).
2

Configure Token Scopes

Select the required scopes:
  • read:user - Read user profile
  • repo - Full access to repositories (required for private starred repos)
The repo scope is needed to access private repositories you’ve starred. If you only have public stars, you can use public_repo instead.
3

Copy Token

Copy the generated token immediately - you won’t be able to see it again.

Step 2: Use PAT in GitStarRecall

1

Navigate to App

Open GitStarRecall and look for the Use Personal Access Token option.
2

Paste Token

Paste your token in the input field. The app will automatically strip common prefixes:
// These are all equivalent:
ghp_1234567890abcdefghijklmnopqrstuvwxyz
Bearer ghp_1234567890abcdefghijklmnopqrstuvwxyz
token ghp_1234567890abcdefghijklmnopqrstuvwxyz
"ghp_1234567890abcdefghijklmnopqrstuvwxyz"
3

Token Validation

The app validates the token on first API call. If successful, you’ll be able to fetch stars.
PAT authentication stores the token in memory only. On page refresh, you’ll need to re-enter the token.

Security Considerations

Token Storage

  • OAuth tokens: Stored in React state (memory only)
  • PAT tokens: Stored in React state (memory only)
  • No persistence: Tokens are never written to localStorage, sessionStorage, or IndexedDB
  • Page refresh: Requires re-authentication

OAuth Security Features

PKCE Flow

Proof Key for Code Exchange prevents authorization code interception attacks

State Validation

Random state parameter prevents CSRF attacks

Client Secret Isolation

Client secret never exposed to browser - only used server-side

Scope Minimization

Requests only read:user and repo scopes - no write access

Content Security Policy

The app enforces a strict CSP with explicit allowlist:
Content-Security-Policy:
  default-src 'self';
  connect-src 'self' https://api.github.com https://github.com;
  script-src 'self' 'wasm-unsafe-eval';
  worker-src 'self' blob:;

Logout and Token Cleanup

To clear authentication:
1

Click Logout

Click the logout button in the app header or settings.
2

Token Cleared

The app clears:
  • Access token from memory
  • Authentication method state
  • LLM provider settings
3

Local Data Preserved

Your local star index and chat sessions are not deleted on logout. Use Delete local data if you want a full reset.

Troubleshooting

Possible causes:
  • Client ID mismatch between VITE_GITHUB_CLIENT_ID and GITHUB_OAUTH_CLIENT_ID
  • Redirect URI mismatch between env vars and GitHub OAuth app settings
  • Client secret incorrect or expired
Solution:
  • Verify all environment variables match exactly
  • Check GitHub OAuth app settings
  • Regenerate client secret if needed
Possible causes:
  • Callback URL in GitHub OAuth app doesn’t match VITE_GITHUB_REDIRECT_URI
  • Production SPA routing not configured correctly
Solution:
  • Ensure callback URL ends with /auth/callback
  • Verify vercel.json or equivalent SPA fallback is configured
  • Check that both VITE_GITHUB_REDIRECT_URI and GITHUB_OAUTH_REDIRECT_URI are identical
Possible causes:
  • Token has Bearer or token prefix (should be raw token only)
  • Token expired or revoked
  • Missing required scopes
Solution:
  • Use raw token: ghp_... only
  • Verify token scopes include read:user and repo
  • Regenerate token if expired
Possible causes:
  • SessionStorage cleared between authorization and callback
  • Multiple OAuth flows started simultaneously
  • Browser privacy mode interfering with sessionStorage
Solution:
  • Don’t clear browser data during OAuth flow
  • Complete one OAuth flow before starting another
  • Try in normal (non-incognito) browser mode
Possible causes:
  • Missing repo scope in OAuth or PAT
  • Token doesn’t have access to organization repositories
Solution:
  • Ensure repo scope is granted (not just public_repo)
  • For organization repos, verify token has organization access
  • Check GitHub token settings for scope details

Next Steps