06.b - Installation-Token-Generation-API
Relevant source files
Purpose and ScopeLink copied!
This document details the /api/admin/generate-token API endpoint, which generates GitHub App installation access tokens for accessing customer repositories. This endpoint serves as the bridge between the admin panel and GitHub's API, enabling the owner to programmatically generate short-lived tokens for repository access.
For information about the admin panel UI that calls this API, see Admin Authentication. For the complete manual workflow that uses these tokens, see Manual Repository Access Workflow.
Sources: app/api/admin/generate-token/route.ts L1-L57
API SpecificationLink copied!
Endpoint DetailsLink copied!
| Property | Value |
|---|---|
| Method | POST |
| Path | /api/admin/generate-token |
| Content-Type | application/json |
| Authentication | Required (ADMIN_PASSWORD) |
| Rate Limiting | None (should be added) |
Request FormatLink copied!
{ "installationId": "12345678", "password": "admin-password-value"}
| Parameter | Type | Required | Description |
|---|---|---|---|
installationId | string | Yes | GitHub App installation ID from Vercel logs or GitHub webhook |
password | string | Yes | Value matching ADMIN_PASSWORD environment variable |
Response FormatLink copied!
Success Response (200):
{ "token": "ghs_16C7e42F292c6912E7710c838347Ae178B4a", "expiresAt": "2024-01-15T12:34:56.789Z", "repositories": [ { "id": 123456789, "name": "customer-repo", "full_name": "customer/customer-repo", "description": "Repository description", "private": true, "html_url": "https://github.com/customer/customer-repo" } ], "user": { "username": "customer", "email": "customer@example.com", "name": "Customer Name" }}
Error Responses:
| Status Code | Response Body | Description |
|---|---|---|
| 401 | {"error": "Unauthorized"} | Invalid or missing password |
| 400 | {"error": "Installation ID is required"} | Missing installationId parameter |
| 500 | {"error": "Failed to generate token"} | GitHub API error or network failure |
Sources: app/api/admin/generate-token/route.ts L4-L56
API Request/Response FlowLink copied!
Sources: app/api/admin/generate-token/route.ts L4-L44
Authentication MechanismLink copied!
Password VerificationLink copied!
The API implements simple password-based authentication by comparing the provided password against the ADMIN_PASSWORD environment variable:
// Password verification logicconst adminPassword = process.env.ADMIN_PASSWORDif (!password || password !== adminPassword) { return new Response(JSON.stringify({ error: "Unauthorized" }), { status: 401, headers: { "Content-Type": "application/json" }, })}
Security Considerations:
| Issue | Impact | Mitigation |
|---|---|---|
| No rate limiting | Brute force attacks possible | Should implement rate limiting middleware |
| Password in request body | Visible in logs | Consider header-based auth or session tokens |
| Plain text comparison | Timing attacks possible | Low risk due to other authentication layers |
| Client-side password storage | localStorage exposure | Admin UI stores auth state, not password itself |
Note: The admin panel stores only an admin_authenticated boolean in localStorage (app/admin/page.tsx L32-L34
), not the password itself. The password is sent with each API request.
Sources: app/api/admin/generate-token/route.ts L8-L15
Internal Processing PipelineLink copied!
Step-by-Step Token GenerationLink copied!
Implementation DetailsLink copied!
1. Token Generation (app/api/admin/generate-token/route.ts L24-L25
):
const tokenData = await getInstallationAccessToken(installationId)
This calls the getInstallationAccessToken function which:
- Creates a GitHub App JWT using
GITHUB_APP_IDandGITHUB_PRIVATE_KEY - Makes a
POSTrequest to/app/installations/{installation_id}/access_tokens - Returns an object with
{token: string, expiresAt: string} - Token expires in 1 hour (GitHub's maximum)
2. Repository Enumeration (app/api/admin/generate-token/route.ts L27-L28
):
const repositories = await getInstallationRepositories(installationId)
This retrieves all repositories accessible to the installation:
- Uses the GitHub App's authentication (not the installation token)
- Calls
/installation/repositoriesendpoint - Returns array of repository objects with metadata
3. User Details Retrieval (app/api/admin/generate-token/route.ts L30-L31
):
const userDetails = await getInstallationDetails(installationId)
This fetches the installation owner's account information:
- Calls
/app/installations/{installation_id}endpoint - Extracts
username,email, andnamefrom account object - Used for repository naming and correlation with payment data
Sources: app/api/admin/generate-token/route.ts L24-L31
Helper Functions and DependenciesLink copied!
Function Reference TableLink copied!
| Function | File | Return Type | Purpose |
|---|---|---|---|
getInstallationAccessToken | lib/github-app.ts | {token: string, expiresAt: string} | Generates installation token via GitHub App JWT |
getInstallationRepositories | lib/github-app.ts | Array<Repository> | Lists accessible repositories |
getInstallationDetails | lib/github-app.ts | {username: string, email: string|null, name: string|null} | Fetches installation owner details |
GitHub App Authentication FlowLink copied!
GitHub App JWT Structure:
- Algorithm: RS256 (RSA Signature with SHA-256)
- Issuer:
GITHUB_APP_ID - Issued At: Current timestamp
- Expiration: 10 minutes from issuance
- Signed with:
GITHUB_PRIVATE_KEY(PEM format)
Installation Token Characteristics:
- Maximum lifespan: 1 hour (GitHub limitation)
- Scope: Limited to repositories selected during installation
- Permissions: Read-only access to Contents and Metadata
- Revocation: Automatic on expiration, or manual via GitHub settings
Sources: lib/github-app.ts
app/api/admin/generate-token/route.ts L24-L25
Usage ExamplesLink copied!
From Admin Panel UILink copied!
The admin panel at /admin calls this API when the "Generate Token" button is clicked:
// Admin UI API callconst response = await fetch("/api/admin/generate-token", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ installationId, password: password // User-entered password }),})const data = await response.json()if (!response.ok) { throw new Error(data.error || "Failed to generate token")}// data contains: {token, expiresAt, repositories, user}
Sources: app/admin/page.tsx L64-L79
From Automation ScriptsLink copied!
The automation scripts (ntfy-godeep-automation.sh, ntfy-godeep-automation-remote.sh) call this API to obtain tokens for cloning repositories:
# Extract installation_id from ntfy notificationINSTALLATION_ID=$(echo "$MESSAGE" | grep -oP 'installation_id=\K[0-9]+')# Call API with authenticationRESPONSE=$(curl -s -X POST "https://godeep.wiki/api/admin/generate-token" \ -H "Content-Type: application/json" \ -d "{ \"installationId\": \"$INSTALLATION_ID\", \"password\": \"$ADMIN_PASSWORD\" }")# Extract token from responseTOKEN=$(echo "$RESPONSE" | jq -r '.token')REPO_URL=$(echo "$RESPONSE" | jq -r '.repositories[0].clone_url')# Use token to clone repositorygit clone "https://x-access-token:${TOKEN}@github.com/${REPO_FULL_NAME}.git"
Sources: app/api/admin/generate-token/route.ts L4-L44
automation scripts
cURL ExampleLink copied!
curl -X POST https://godeep.wiki/api/admin/generate-token \ -H "Content-Type: application/json" \ -d '{ "installationId": "12345678", "password": "your-admin-password" }'
Expected Response:
{ "token": "ghs_16C7e42F292c6912E7710c838347Ae178B4a", "expiresAt": "2024-01-15T13:34:56.789Z", "repositories": [ { "id": 123456789, "name": "example-repo", "full_name": "customer/example-repo", "private": true, "clone_url": "https://github.com/customer/example-repo.git" } ], "user": { "username": "customer", "email": "customer@example.com", "name": "Customer Name" }}
Sources: app/api/admin/generate-token/route.ts L33-L44
Error HandlingLink copied!
Error Scenarios and ResponsesLink copied!
Common Error CasesLink copied!
| Error Type | Cause | Status Code | Error Message | Resolution |
|---|---|---|---|---|
| Invalid Password | Password doesn't match ADMIN_PASSWORD | 401 | "Unauthorized" | Verify ADMIN_PASSWORD environment variable |
| Missing Installation ID | installationId not provided in request | 400 | "Installation ID is required" | Include valid installationId in request body |
| Invalid Installation ID | Installation ID doesn't exist or app not installed | 500 | GitHub API error message | Verify installation ID from logs; check if installation still exists |
| Expired GitHub App Key | GITHUB_PRIVATE_KEY expired or revoked | 500 | JWT signature error | Regenerate GitHub App private key |
| Network Timeout | GitHub API unreachable | 500 | Connection timeout | Retry request; check GitHub status |
| Rate Limit Exceeded | Too many GitHub API calls | 500 | Rate limit error | Wait for rate limit reset; implement caching |
Error LoggingLink copied!
All errors are logged to the console with full error details:
catch (error: any) { console.error("Token generation error:", error) return new Response( JSON.stringify({ error: error.message || "Failed to generate token", }), { status: 500, headers: { "Content-Type": "application/json" }, } )}
This provides visibility in Vercel logs for debugging failed token generation attempts.
Sources: app/api/admin/generate-token/route.ts L45-L56
Security ConsiderationsLink copied!
Vulnerability AssessmentLink copied!
| Vulnerability | Severity | Current State | Recommendation |
|---|---|---|---|
| No rate limiting | High | No protection | Implement rate limiting per IP or session |
| Password in request body | Medium | Logged in Vercel | Use Authorization header or session cookies |
| Client-exposed password env | Medium | NEXT_PUBLIC_ADMIN_PASSWORD accessible | Remove NEXT_PUBLIC_ prefix; use server-side only |
| No CORS restrictions | Low | Open to all origins | Add CORS headers for production domain only |
| No request size limits | Low | Could accept large payloads | Add body size validation |
Token Security PropertiesLink copied!
Short Lifespan:
- Installation tokens expire after 1 hour (GitHub maximum)
- Reduces window of exposure if token is compromised
- Displayed in admin UI:
"Token expires at: {new Date(tokenData.expiresAt).toLocaleString()}"(app/admin/page.tsx L229 )
Scope Limitation:
- Token only accesses repositories selected during installation
- Read-only permissions (Contents + Metadata)
- Cannot write, delete, or modify repositories
No Persistent Storage:
- Tokens are generated on-demand, not stored in database
- Each request creates a fresh token
- No long-lived credentials in system
Best Practices for Token UsageLink copied!
- Immediate Use: Generate token immediately before cloning repository
- Short-Lived Processes: Complete repository operations within 1 hour
- No Logging: Avoid logging full token values (use masked versions:
ghs_****...****) - Secure Transmission: Always use HTTPS (enforced by Vercel in production)
- Cleanup: Delete cloned repositories after processing to prevent token reuse
Sources: app/api/admin/generate-token/route.ts L8-L15
Response Data StructureLink copied!
Token Object FieldsLink copied!
| Field | Type | Example | Description |
|---|---|---|---|
token | string | "ghs_16C7e..." | GitHub installation access token (begins with ghs_) |
expiresAt | string (ISO 8601) | "2024-01-15T12:34:56.789Z" | Token expiration timestamp |
Repository Object FieldsLink copied!
Each item in the repositories array contains:
| Field | Type | Example | Description |
|---|---|---|---|
id | number | 123456789 | GitHub repository ID |
name | string | "example-repo" | Repository name (without owner) |
full_name | string | "customer/example-repo" | Full repository path |
description | string | null | "Project description" | Repository description |
private | boolean | true | Whether repository is private |
html_url | string | "https://github.com/..." | Web URL for repository |
clone_url | string | "https://github.com/..." | HTTPS clone URL |
User Object FieldsLink copied!
| Field | Type | Example | Description |
|---|---|---|---|
username | string | "customer" | GitHub username of installation owner |
email | string | null | "customer@example.com" | Email address (may be null if private) |
name | string | null | "Customer Name" | Display name (may be null) |
Usage in Admin UI:
The admin panel uses this data to:
- Display customer information (app/admin/page.tsx L223-L227 )
- Format repository names for cloning:
{email}-{reponame}(app/admin/page.tsx L91-L98 ) - Show clone commands with embedded token (app/admin/page.tsx L256-L258 )
- Provide one-click copy buttons for common operations (app/admin/page.tsx L319-L342 )
Sources: app/api/admin/generate-token/route.ts L33-L44
Refresh this wiki
Last indexed: 23 November 2025 (922b35)
On this page
- Installation Token Generation API
- Purpose and Scope
- API Specification
- Endpoint Details
- Request Format
- Response Format
- API Request/Response Flow
- Authentication Mechanism
- Password Verification
- Internal Processing Pipeline
- Step-by-Step Token Generation
- Implementation Details
- Helper Functions and Dependencies
- Function Reference Table
- GitHub App Authentication Flow
- Usage Examples
- From Admin Panel UI
- From Automation Scripts
- cURL Example
- Error Handling
- Error Scenarios and Responses
- Common Error Cases
- Error Logging
- Security Considerations
- Vulnerability Assessment
- Token Security Properties
- Best Practices for Token Usage
- Response Data Structure
- Token Object Fields
- Repository Object Fields
- User Object Fields
Ask Devin about godeep.wiki-jb
Syntax error in text
mermaid version 11.4.1