kavachOS
AuthenticationOAuth providers

GitHub

Sign in with GitHub using OAuth 2.0.

Get credentials

Register an OAuth App

Go to github.com/settings/applications/new (personal account) or Organization Settings > Developer Settings > OAuth Apps for an org app.

  • Application name: your app name
  • Homepage URL: https://example.com
  • Authorization callback URL: https://auth.example.com/auth/oauth/github/callback

Copy credentials

After creating the app, copy the Client ID. Click Generate a new client secret and copy the secret immediately — GitHub only shows it once.

GitHub also supports GitHub Apps, which have more granular permissions and work across organizations. OAuth Apps are simpler for sign-in use cases.

Configuration

lib/kavach.ts
import { createKavach } from '@kavachos/core';
import { oauth } from '@kavachos/core/plugins/oauth';

const kavach = await createKavach({
  database: { provider: 'postgres', url: process.env.DATABASE_URL! },
  secret: process.env.KAVACH_SECRET!,
  baseUrl: 'https://auth.example.com',
  plugins: [
    oauth({
      providers: [
        {
          id: 'github',
          clientId: process.env.GITHUB_CLIENT_ID!,
          clientSecret: process.env.GITHUB_CLIENT_SECRET!,
        },
      ],
    }),
  ],
});
lib/kavach.ts
oauth({
  providers: [
    {
      id: 'github',
      clientId: process.env.GITHUB_CLIENT_ID!,
      clientSecret: process.env.GITHUB_CLIENT_SECRET!,
      scopes: ['user:email', 'read:org'],
    },
  ],
})
GITHUB_CLIENT_ID=Ov23li...
GITHUB_CLIENT_SECRET=...

Scopes

Default scope: user:email

ScopeWhat it unlocks
user:emailRead the user's email addresses
read:userRead the user's profile data
read:orgRead organization membership
repoAccess private repositories

User data returned

FieldSourceNotes
idid fieldStable numeric GitHub user ID
emailPrimary verified emailFetched separately if not public
namename fieldDisplay name, may be null
imageavatar_urlGitHub avatar URL

GitHub users can set their email to private. KavachOS fetches the primary verified email from the /user/emails endpoint using the user:email scope, so you still get it even if the profile email is hidden.

On this page