Authentication
GitHub OAuth, GitHub App setup, JWT tokens, and session management in CodePilot.
CodePilot uses GitHub for authentication via two mechanisms: GitHub OAuth (user login) and GitHub App (repository access and webhooks).
GitHub OAuth
Users authenticate with their GitHub account. The OAuth flow:
User Clicks "Login with GitHub"
The frontend redirects to GitHub's authorization endpoint with the CodePilot OAuth App's client_id.
GitHub Redirects Back
After authorization, GitHub redirects to the callback URL with a temporary code.
API Exchanges Code for Token
The API exchanges the code for an access token using GITHUB_CLIENT_ID and GITHUB_CLIENT_SECRET.
const tokenResponse = await fetch(
"https://github.com/login/oauth/access_token",
{
method: "POST",
headers: { Accept: "application/json" },
body: JSON.stringify({
client_id: process.env.GITHUB_CLIENT_ID,
client_secret: process.env.GITHUB_CLIENT_SECRET,
code: authCode,
}),
}
);Session Created
A session is created with JWT access and refresh tokens. The session cookie is set on the response.
GitHub App
The GitHub App provides repository access and webhook delivery.
Setup
Create a GitHub App
Go to github.com/settings/apps and create a new GitHub App.
Required fields:
- App name: CodePilot (or your custom name)
- Homepage URL: Your production URL
- Webhook URL:
https://your-domain.com/webhooks/github - Webhook secret: Generate with
openssl rand -hex 32
Configure Permissions
| Permission | Access | Purpose |
|---|---|---|
| Repository contents | Read | Clone and read source code |
| Pull requests | Read & Write | Post AI code reviews |
| Metadata | Read | Repository metadata |
Subscribe to Events
push— Triggers incremental ingestionpull_request— Triggers AI code reviewinstallation— Tracks app installations
Generate a Private Key
Download the private key and add it to your .env.api as GITHUB_PRIVATE_KEY.
Private Key Format
The private key must be a single line with \n for newlines, or stored in a file and referenced.
JWT Tokens
CodePilot uses JWT (JSON Web Tokens) for stateless authentication:
| Token | Purpose | Lifetime |
|---|---|---|
| Access Token | API request authentication | Short-lived (15 min) |
| Refresh Token | Obtain new access tokens | Long-lived (7 days) |
// Generate access token
const accessToken = jwt.sign(
{ userId: user.id },
process.env.ACCESS_TOKEN_SECRET,
{ expiresIn: "15m" }
);
// Generate refresh token
const refreshToken = jwt.sign(
{ userId: user.id, sessionId: session.id },
process.env.REFRESH_TOKEN_SECRET,
{ expiresIn: "7d" }
);Session Management
Sessions are stored in PostgreSQL and linked to users:
model Session {
id String @id @default(cuid())
userId String
user User @relation(fields: [userId], references: [id])
token String @unique
expiresAt DateTime
createdAt DateTime @default(now())
}Encryption
Sensitive data (like GitHub tokens) is encrypted at rest using AES-256-GCM:
import { createCipheriv, createDecipheriv, randomBytes } from "crypto";
function encrypt(text: string, secret: string): string {
const iv = randomBytes(16);
const cipher = createCipheriv("aes-256-gcm", Buffer.from(secret, "hex"), iv);
// ... encryption logic
}The encryption key is configured via the ENCRYPTION_SECRET environment variable (256-bit hex key).