Skip to main content
Nectr uses GitHub OAuth to authenticate users and access their repositories. This guide walks you through creating and configuring a GitHub OAuth App.

Overview

GitHub OAuth enables:
  • User Authentication - Users sign in with their GitHub account
  • Repository Access - Nectr can read PR data and post review comments
  • Organization Access - Users can grant access to organization repositories
OAuth Scopes Required:
  • repo - Full control of private repositories
  • read:user - Read user profile data
  • user:email - Access user email addresses
  • read:org - Read organization membership

Creating a GitHub OAuth App

1

Navigate to GitHub Developer Settings

Go to github.com/settings/developers and click New OAuth App.Or navigate manually:
  1. GitHub → Settings
  2. Developer settings (bottom of sidebar)
  3. OAuth Apps → New OAuth App
2

Configure OAuth App Details

Fill in the application details:
FieldValue
Application nameNectr AI PR Review (or your preferred name)
Homepage URLYour frontend URL (e.g., https://your-app.vercel.app)
Application descriptionOptional: “AI-powered pull request review agent”
Authorization callback URLhttps://your-backend.up.railway.app/auth/github/callback
The Authorization callback URL must point to your backend API, not your frontend.Format: {BACKEND_URL}/auth/github/callbackExamples:
  • Development: http://localhost:8000/auth/github/callback
  • Production: https://your-backend.up.railway.app/auth/github/callback
3

Save Client ID and Secret

After creating the app, GitHub will display:
  • Client ID - A public identifier (e.g., Iv1.abc123...)
  • Client Secret - A secret key (click “Generate a new client secret”)
Copy both values to your .env file:
GITHUB_CLIENT_ID=Iv1.abc123...
GITHUB_CLIENT_SECRET=your-client-secret
Store the client secret securely. You won’t be able to see it again after leaving the page.

OAuth Flow

Nectr implements a standard OAuth 2.0 authorization code flow with CSRF protection.

Step-by-Step Process

Frontend redirects to GET /auth/github
// Frontend code
window.location.href = `${API_URL}/auth/github`;
Backend generates a random state token and stores it in the database with a 10-minute expiration.
# app/auth/router.py:22-37
state = secrets.token_urlsafe(32)
expires_at = datetime.now(timezone.utc) + timedelta(minutes=10)

oauth_state = OAuthState(state=state, expires_at=expires_at)
db.add(oauth_state)
await db.commit()
This protects against CSRF attacks by ensuring the callback comes from a legitimate request.
Backend redirects user to GitHub’s OAuth authorization page.
github_url = (
    f"https://github.com/login/oauth/authorize"
    f"?client_id={settings.GITHUB_CLIENT_ID}"
    f"&scope=repo,read:user,user:email,read:org"
    f"&state={state}"
)
return RedirectResponse(url=github_url)
GitHub shows an authorization screen asking the user to grant access to:
  • Their public and private repositories
  • Their profile information
  • Organization memberships (if any)
After approval, GitHub redirects to the callback URL with:
  • code - Temporary authorization code
  • state - The CSRF token we provided
# app/auth/router.py:48-84

# 1. Validate CSRF state
oauth_state = await db.execute(
    select(OAuthState).where(
        OAuthState.state == state,
        OAuthState.expires_at > datetime.now(timezone.utc),
    )
)
if not oauth_state:
    raise HTTPException(status_code=400, detail="Invalid or expired OAuth state")

# 2. Exchange code for access token
access_token = await exchange_code_for_token(code)

# 3. Fetch user profile from GitHub
gh_user = await fetch_github_user(access_token)

Token Security

Encryption

GitHub OAuth tokens are encrypted before being stored in the database using the SECRET_KEY environment variable.
# app/auth/token_encryption.py
from cryptography.fernet import Fernet

cipher = Fernet(settings.SECRET_KEY.encode())

def encrypt_token(token: str) -> str:
    return cipher.encrypt(token.encode()).decode()

def decrypt_token(encrypted_token: str) -> str:
    return cipher.decrypt(encrypted_token.encode()).decode()
If you change SECRET_KEY, all existing encrypted tokens will become invalid and users will need to re-authenticate.

JWT Cookies

Nectr uses JWT tokens stored in httpOnly cookies for session management:
PropertyDevelopmentProduction
httponlytruetrue
securefalsetrue
samesitelaxnone
max_age1440 minutes (24h)1440 minutes (24h)
Why httpOnly? Prevents XSS attacks by making the cookie inaccessible to JavaScript. Why SameSite=none in production? Allows cross-origin requests when frontend and backend are on different domains.

Granting Organization Access

By default, users can only access their personal repositories. To access organization repositories:
1

User Clicks Reconnect

Navigate to GET /auth/github/reconnect endpoint.This revokes the current OAuth token and redirects to a fresh GitHub authorization screen.
# app/auth/router.py:148-188
await revoke_github_token(access_token)

# Redirect to fresh OAuth flow
github_url = (
    f"https://github.com/login/oauth/authorize"
    f"?client_id={settings.GITHUB_CLIENT_ID}"
    f"&scope=repo,read:user,user:email,read:org"
    f"&state={new_state}"
)
2

GitHub Shows Org Access Screen

GitHub displays an authorization screen with organization access requests.Users can:
  1. Grant access to specific organizations
  2. Approve access for the OAuth app
3

User Completes Fresh OAuth Flow

After granting access, the user completes the OAuth flow again with the new permissions.The new token will have access to the granted organization repositories.

Testing OAuth Locally

Local Development Setup

  1. Create a separate OAuth App for local development GitHub doesn’t allow localhost in production OAuth apps, so create a dedicated dev app:
    • Homepage URL: http://localhost:3000
    • Callback URL: http://localhost:8000/auth/github/callback
  2. Configure local environment
    # .env
    GITHUB_CLIENT_ID=Iv1.your-dev-client-id
    GITHUB_CLIENT_SECRET=your-dev-client-secret
    BACKEND_URL=http://localhost:8000
    FRONTEND_URL=http://localhost:3000
    APP_ENV=development
    
  3. Test the flow
    # Start backend
    uvicorn app.main:app --reload --port 8000
    
    # Visit
    http://localhost:8000/auth/github
    
    You should be redirected to GitHub, then back to your frontend dashboard after approval.
Make sure your frontend is configured to include credentials in API requests:
// axios configuration
const api = axios.create({
  baseURL: process.env.NEXT_PUBLIC_API_URL,
  withCredentials: true,  // Required for httpOnly cookies
});

Troubleshooting

Error: redirect_uri_mismatchCause: The callback URL in your GitHub OAuth App doesn’t match the URL Nectr is using.Solution:
  1. Check your BACKEND_URL in .env
  2. Verify the callback URL in GitHub OAuth App settings matches: {BACKEND_URL}/auth/github/callback
  3. Ensure there are no trailing slashes or typos
Error: Invalid or expired OAuth stateCause:
  • State token expired (>10 minutes)
  • Database connection issue
  • CSRF token mismatch
Solution:
  1. Try the login flow again (state tokens expire after 10 minutes)
  2. Check database connectivity
  3. Ensure cookies are enabled in your browser
Error: Session expired — please log out and sign in againCause: SECRET_KEY changed after the user authenticated.Solution:
  • User must log out and sign in again
  • All encrypted tokens are invalidated when SECRET_KEY changes
  • Avoid changing SECRET_KEY in production
Cause: User hasn’t granted organization access to the OAuth app.Solution:
  1. Navigate to /auth/github/reconnect endpoint
  2. This will revoke the current token and show a fresh GitHub authorization screen
  3. Grant access to the desired organizations
  4. Complete the OAuth flow again

API Endpoints

MethodEndpointDescription
GET/auth/githubStart OAuth flow
GET/auth/github/callbackOAuth callback (handles code exchange)
GET/auth/meGet current authenticated user
GET/auth/github/reconnectRevoke token and re-authorize (for org access)
POST/auth/logoutClear auth cookie
Source: app/auth/router.py:18-203

Next Steps

Environment Variables

View all configuration options

Webhooks

Configure GitHub webhooks for PR events

Build docs developers (and LLMs) love