GitProfileLens turns a public GitHub profile into a transparent 0–100 presentation score with actionable recommendations. Public audits require no login. An optional GitHub App connection can also audit authorized private repositories and identify projects worth preparing for a public portfolio.
GitProfileLens evaluates presentation and discoverability, not developer ability, employability, code quality, or engineering skill.
Enter any GitHub username without signing in. The public audit:
- Fetches every public repository owned by the account.
- Calculates the public GitHub Profile Score and six explainable categories.
- Audits names, descriptions, READMEs, topics, licenses, demos, and maintenance.
- Ranks actionable portfolio recommendations.
- Supports shareable
?user=USERNAMElinks and downloadable score cards. - Explores public repository metadata and exports it to Markdown.
- Provides the public JSON endpoint
GET /api/report?user=USERNAME.
Sign in with GitHub and install the GitHub App on all or selected repositories. The private audit:
- Retrieves only repositories available to both the signed-in user and the app installation.
- Focuses on repositories owned by the signed-in account.
- Reuses the deterministic repository presentation checks.
- Labels each repository as Private or Public.
- Classifies projects as strong portfolio candidates, worth polishing, or needing presentation work.
- Exports Markdown containing public repositories, authorized private repositories, or both.
Private repositories never affect the public GitHub Profile Score. Private identifiers are not included in public URLs, score cards, public metadata endpoints, or /api/report. Private details enter Markdown only when the authenticated user explicitly selects a private or combined export.
The deterministic scoring engine lives in audit.js and is shared by the browser, serverless routes, and tests. Each repository receives scores for:
- Repository presentation: name clarity and consistency.
- Descriptions: specificity, useful length, placeholder text, and basic polish.
- README quality: presence, useful length, overview, setup, usage, examples, code samples, visuals, and contribution guidance.
- Discoverability: topics, license, and a demo link where useful.
- Maintenance: push recency while treating archived projects as intentionally complete.
The public profile score aggregates those repository results and adds portfolio focus. Every finding includes a severity, reason, suggested action, and a factual or advisory classification. Unknown README data receives a neutral score and is marked unverified.
docs/scoring.md documents every rule and weight, what the score intentionally does not measure, known limitations, and how to change scoring safely.
GitProfileLens uses the GitHub App web authorization flow and requests read-only repository access. Users choose which repositories the app may access through GitHub's installation interface.
- GitHub access and refresh tokens are encrypted with AES-256-GCM inside an
HttpOnly, same-site session cookie. - Production cookies use
Secureand expire after eight hours. - OAuth requests use unpredictable, short-lived state values that are verified before callback processing.
- Authenticated endpoints send private, no-store cache headers and are not eligible for shared CDN caching.
- Browser JavaScript receives only safe sign-in identity data, never raw tokens or session secrets.
- Private repository responses are processed for the current request and are not permanently stored by GitProfileLens.
- Private Markdown reports are generated locally in the browser and cleared from page state on logout.
- Logout clears the GitProfileLens session cookie. It does not sign the user out of GitHub.
The server necessarily receives authorized GitHub API responses while producing an audit. Avoid granting the GitHub App access to repositories you do not want GitProfileLens to process.
The JSON API remains public-only:
GET /api/report?user=quangshuynh
It returns normalized public repository metadata and never uses the signed-in browser session to add private data. The endpoint requires the server-side GITHUB_TOKEN.
The anonymous public experience has no client build step:
git clone https://github.com/quangshuynh/gitprofilelens.git
cd gitprofilelens
python -m http.server 8000Open http://localhost:8000. README and pinned-repository checks are marked unverified when the Vercel functions are unavailable.
Install the Vercel CLI, create .env.local, and run vercel dev:
GITHUB_TOKEN=your_public_metadata_token
GITHUB_APP_CLIENT_ID=your_github_app_client_id
GITHUB_APP_CLIENT_SECRET=your_github_app_client_secret
GITHUB_APP_CALLBACK_URL=http://localhost:3000/api/auth/callback
GITHUB_APP_INSTALL_URL=https://github.com/apps/YOUR_APP_SLUG/installations/new
SESSION_SECRET=at_least_32_random_characters
vercel devAdd http://localhost:3000/api/auth/callback as an additional callback URL in the GitHub App while testing locally. The value of GITHUB_APP_CALLBACK_URL must exactly match the callback used by that environment.
Never commit .env.local, client secrets, access tokens, refresh tokens, or session secrets. Local environment files and .vercel are ignored by Git.
Create a GitHub App in GitHub Settings under Developer settings, then use these values:
| Setting | Value |
|---|---|
| GitHub App name | GitProfileLens, or another available name |
| Homepage URL | https://gitprofilelens.vercel.app/ |
| Callback URL | https://gitprofilelens.vercel.app/api/auth/callback |
| Callback wildcard matching | Disabled |
| Request user authorization during installation | Disabled |
| Setup URL | https://gitprofilelens.vercel.app/ |
| Redirect on update | Enabled |
| Webhook | Disabled |
| Where can this GitHub App be installed? | Any account for a public app, or only your account for personal testing |
Repository permissions:
- Metadata: Read-only. GitHub may apply this automatically.
- Contents: Read-only. This is required to retrieve root README content.
- Every other repository and organization permission: No access.
- Subscribe to no webhook events.
Under the GitHub App's Optional Features, keep User-to-server token expiration enabled. GitHub's expiring access tokens last eight hours and can be refreshed by the server.
After creating the app:
- Generate a client secret.
- Copy the Client ID, not the numeric App ID, into
GITHUB_APP_CLIENT_ID. - Set
GITHUB_APP_INSTALL_URLtohttps://github.com/apps/YOUR_APP_SLUG/installations/new. - Install the app and select either all repositories or only selected repositories.
- Do not generate or upload a private key. This feature uses user access tokens and does not authenticate as the app installation itself.
Configure these in the Vercel project settings for Production:
| Variable | Purpose |
|---|---|
GITHUB_TOKEN |
Existing server-only token for public pin and README enrichment |
GITHUB_APP_CLIENT_ID |
GitHub App Client ID |
GITHUB_APP_CLIENT_SECRET |
GitHub App client secret |
GITHUB_APP_CALLBACK_URL |
https://gitprofilelens.vercel.app/api/auth/callback |
GITHUB_APP_INSTALL_URL |
https://github.com/apps/YOUR_APP_SLUG/installations/new |
SESSION_SECRET |
Random secret of at least 32 characters used to derive the session-encryption key |
Redeploy after changing environment variables. Preview deployments need their own exact callback URL registered with GitHub, so use the stable production domain for routine authentication testing.
gitprofilelens/
|-- api/
| |-- auth/
| | |-- authenticated-session.js # decrypts and refreshes server-side session material
| | |-- callback.js # verifies state and completes GitHub authorization
| | |-- github.js # starts GitHub authorization
| | |-- logout.js # clears authentication cookies
| | |-- session-crypto.js # authenticated encryption and cookie helpers
| | `-- session.js # safe browser authentication state
| |-- github-metadata.js # public GraphQL enrichment and README analysis
| |-- pinned-repositories.js # public supplemental metadata endpoint
| |-- private-repositories.js # authenticated authorized-repository endpoint
| `-- report.js # public-only JSON report endpoint
|-- tests/ # unit, API, security, and browser tests
|-- audit.js # deterministic scoring and normalization
|-- index.html # accessible application structure
|-- share.js # pure sharing and score-card helpers
|-- script.js # browser state, fetching, rendering, and isolation
|-- styles.css # responsive visual system
`-- package.json # test and syntax-check scripts
The public supplemental endpoints may cache successful public responses briefly. Authentication and private repository endpoints use private, no-store responses. The application has no database, saved audit history, repository cloning, source-code analysis, webhooks, or background jobs.
npm test
npm run check
npm run test:browserTests cover deterministic scoring, public report isolation, OAuth state verification, encrypted session behavior, logout, authorized-repository pagination, owner filtering, README analysis, safe GitHub errors, private cache headers, three-scope Markdown export, and browser-level isolation from public scoring, sharing, score cards, and URLs.
Vercel is required for the full public metadata and private GitHub App features. Configure all documented environment variables before deployment.
GitHub Pages can host only the static public client. Public repository fetching, basic auditing, sharing, and Markdown export work, but serverless README enrichment, the JSON API, and private repository authentication do not.
- Unauthenticated public REST requests have a lower GitHub rate limit.
- The public GraphQL README query covers the first 100 public repositories and common root README filenames.
- Private auditing retrieves the preferred root README but does not clone repositories or analyze source code.
- The private view currently focuses on repositories owned by the signed-in user, not organization administration.
- Private report APIs, saved audits, and combined public/private scores are intentionally excluded. Private Markdown export is available only through the authenticated browser view.
- README structure and size are presentation signals and cannot determine writing or implementation quality.
- A public share URL re-fetches current public data; no audit snapshot is stored.
Think a scoring rule should work differently? Start a discussion or open an issue with a concrete example and rationale.
- Create a focused branch.
- Keep scoring changes deterministic and document their rationale.
- Add or update behavior-focused tests.
- Run
npm test,npm run check, andnpm run test:browser. - Open a pull request describing user-facing changes and tradeoffs.
Feel free to use, modify, and build on this project under the MIT License.

