DeepWiki

06.b - Installation-Token-Generation-API

Relevant source files

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


PropertyValue
MethodPOST
Path/api/admin/generate-token
Content-Typeapplication/json
AuthenticationRequired (ADMIN_PASSWORD)
Rate LimitingNone (should be added)
{  "installationId": "12345678",  "password": "admin-password-value"}
ParameterTypeRequiredDescription
installationIdstringYesGitHub App installation ID from Vercel logs or GitHub webhook
passwordstringYesValue matching ADMIN_PASSWORD environment variable

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 CodeResponse BodyDescription
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


Sources: app/api/admin/generate-token/route.ts L4-L44

lib/github-app.ts


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:

IssueImpactMitigation
No rate limitingBrute force attacks possibleShould implement rate limiting middleware
Password in request bodyVisible in logsConsider header-based auth or session tokens
Plain text comparisonTiming attacks possibleLow risk due to other authentication layers
Client-side password storagelocalStorage exposureAdmin 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

app/admin/page.tsx L30-L36


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_ID and GITHUB_PRIVATE_KEY
  • Makes a POST request 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/repositories endpoint
  • 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, and name from account object
  • Used for repository naming and correlation with payment data

Sources: app/api/admin/generate-token/route.ts L24-L31

lib/github-app.ts


FunctionFileReturn TypePurpose
getInstallationAccessTokenlib/github-app.ts{token: string, expiresAt: string}Generates installation token via GitHub App JWT
getInstallationRepositorieslib/github-app.tsArray<Repository>Lists accessible repositories
getInstallationDetailslib/github-app.ts{username: string, email: string|null, name: string|null}Fetches installation owner details

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


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

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 -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 TypeCauseStatus CodeError MessageResolution
Invalid PasswordPassword doesn't match ADMIN_PASSWORD401"Unauthorized"Verify ADMIN_PASSWORD environment variable
Missing Installation IDinstallationId not provided in request400"Installation ID is required"Include valid installationId in request body
Invalid Installation IDInstallation ID doesn't exist or app not installed500GitHub API error messageVerify installation ID from logs; check if installation still exists
Expired GitHub App KeyGITHUB_PRIVATE_KEY expired or revoked500JWT signature errorRegenerate GitHub App private key
Network TimeoutGitHub API unreachable500Connection timeoutRetry request; check GitHub status
Rate Limit ExceededToo many GitHub API calls500Rate limit errorWait for rate limit reset; implement caching

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


VulnerabilitySeverityCurrent StateRecommendation
No rate limitingHighNo protectionImplement rate limiting per IP or session
Password in request bodyMediumLogged in VercelUse Authorization header or session cookies
Client-exposed password envMediumNEXT_PUBLIC_ADMIN_PASSWORD accessibleRemove NEXT_PUBLIC_ prefix; use server-side only
No CORS restrictionsLowOpen to all originsAdd CORS headers for production domain only
No request size limitsLowCould accept large payloadsAdd body size validation

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
  1. Immediate Use: Generate token immediately before cloning repository
  2. Short-Lived Processes: Complete repository operations within 1 hour
  3. No Logging: Avoid logging full token values (use masked versions: ghs_****...****)
  4. Secure Transmission: Always use HTTPS (enforced by Vercel in production)
  5. Cleanup: Delete cloned repositories after processing to prevent token reuse

Sources: app/api/admin/generate-token/route.ts L8-L15

app/admin/page.tsx L229


FieldTypeExampleDescription
tokenstring"ghs_16C7e..."GitHub installation access token (begins with ghs_)
expiresAtstring (ISO 8601)"2024-01-15T12:34:56.789Z"Token expiration timestamp

Each item in the repositories array contains:

FieldTypeExampleDescription
idnumber123456789GitHub repository ID
namestring"example-repo"Repository name (without owner)
full_namestring"customer/example-repo"Full repository path
descriptionstring | null"Project description"Repository description
privatebooleantrueWhether repository is private
html_urlstring"https://github.com/..."Web URL for repository
clone_urlstring"https://github.com/..."HTTPS clone URL
FieldTypeExampleDescription
usernamestring"customer"GitHub username of installation owner
emailstring | null"customer@example.com"Email address (may be null if private)
namestring | null"Customer Name"Display name (may be null)

Usage in Admin UI:

The admin panel uses this data to:

Sources: app/api/admin/generate-token/route.ts L33-L44

app/admin/page.tsx L91-L98

app/admin/page.tsx L223-L294

Refresh this wiki

Last indexed: 23 November 2025 (922b35)

On this page

Ask Devin about godeep.wiki-jb

Syntax error in text

mermaid version 11.4.1

06.b - Installation-Token-Generation-API | DeepWiki | godeep.wiki