mcpField
O
oauth-integrations

oauth-integrations

github.com/jezwebSecurity1.1k356 installsUpdated 3w ago
Repository

About oauth-integrations

A guide to implementing GitHub and Microsoft OAuth in edge runtimes such as Cloudflare Workers. It is for developers building authentication flows, with practical notes on runtime constraints, required parameters, token handling, and common errors.

Key features

  1. 01GitHub OAuth requests and token exchange
  2. 02Handle private GitHub email addresses
  3. 03Manual Microsoft Entra OAuth flow
  4. 04Configure scopes for Microsoft Graph
  5. 05Review tenant options and token lifetimes

Use cases

  1. 01Add GitHub sign-in to Cloudflare Workers
  2. 02Fetch user profiles from Microsoft Graph
  3. 03Implement refresh tokens for long sessions

Install

Copy the command and run it in a terminal.

$npx skills add https://github.com/jezweb/claude-skills --skill oauth-integrations

After installing, type/oauth-integrationsin Claude Code to confirm it loaded.

Bundled files

References and scripts installed along with SKILL.md.

README.md
.claude-plugin/
plugin.json
rules/
github-oauth.md
microsoft-oauth.md

Details

From the project README

OAuth Integrations for Edge Environments

Implement GitHub and Microsoft OAuth in Cloudflare Workers and other edge runtimes.

GitHub OAuth

Required Headers

GitHub API has strict requirements that differ from other providers.

HeaderRequirement
User-AgentREQUIRED - Returns 403 without it
Acceptapplication/vnd.github+json recommended
const resp = await fetch('https://api.github.com/user', {
  headers: {
    Authorization: `Bearer ${accessToken}`,
    'User-Agent': 'MyApp/1.0',  // Required!
    'Accept': 'application/vnd.github+json',
  },
});
Private Email Handling

GitHub users can set email to private (/user returns email: null).

if (!userData.email) {
  const emails = await fetch('https://api.github.com/user/emails', { headers })
    .then(r => r.json());
  userData.email = emails.find(e => e.primary && e.verified)?.email;
}

Requires user:email scope.

Token Exchange

Token exchange returns form-encoded by default. Add Accept header for JSON:

const tokenResponse = await fetch('https://github.com/login/oauth/access_token', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/x-www-form-urlencoded',
    'Accept': 'application/json',  // Get JSON response
  },
  body: new URLSearchParams({ code, client_id, client_secret, redirect_uri }),
});
GitHub OAuth Notes
IssueSolution
Callback URLMust be EXACT - no wildcards, no subdirectory matching
Token exchange returns form-encodedAdd 'Accept': 'application/json' header
Tokens don't expireNo refresh flow needed, but revoked = full re-auth

Microsoft Entra (Azure AD) OAuth

Why MSAL Doesn't Work in Workers

MSAL.js depends on:

  • Browser APIs (localStorage, sessionStorage, DOM)
  • Node.js crypto module

Cloudflare's V8 isolate runtime has neither. Use manual OAuth instead:

  1. Manual OAuth URL construction
  2. Direct token exchange via fetch
  3. JWT validation with jose library
Required Scopes
// For user identity (email, name, profile picture)
const scope = 'openid email profile User.Read';

// For refresh tokens (long-lived sessions)
const scope = 'openid email profile User.Read offline_access';

Critical: User.Read is required for Microsoft Graph /me endpoint. Without it, token exchange succeeds but user info fetch returns 403.

User Info Endpoint
// Microsoft Graph /me endpoint
const resp = await fetch('https://graph.microsoft.com/v1.0/me', {
  headers: { Authorization: `Bearer ${accessToken}` },
});

// Email may be in different fields
const email = data.mail || data.userPrincipalName;
Tenant Configuration
Tenant ValueWho Can Sign In
commonAny Microsoft account (personal + work)
organizationsWork/school accounts only
consumersPersonal Microsoft accounts only
{tenant-id}Specific organization only
Azure Portal Setup
  1. App Registration → New registration
  2. Platform: Web (not SPA) for server-side OAuth
  3. Redirect URIs: Add both /callback and /admin/callback
  4. Certificates & secrets → New client secret
Token Lifetimes
Token TypeDefault LifetimeNotes
Access token60-90 minutesConfigurable via token lifetime policies
Refresh token90 daysRevoked on password change
ID token60 minutesSame as access token

Best Practice: Always request offline_access scope and implement refresh token flow for sessions longer than 1 hour.

Common Corrections

If Claude suggests...Use instead...
GitHub fetch without User-AgentAdd 'User-Agent': 'AppName/1.0' (REQUIRED)
Using MSAL.js in WorkersManual OAuth + jose for JWT validation
Microsoft scope without User.ReadAdd User.Read scope
Fetching email from token claims onlyUse Graph /me endpoint

Error Reference

GitHub Errors
ErrorCauseFix
403 ForbiddenMissing User-Agent headerAdd User-Agent header
email: nullUser has private emailFetch /user/emails with user:email scope
Microsoft Errors
ErrorCauseFix
AADSTS50058Silent auth failedUse interactive flow
AADSTS700084Refresh token expiredRe-authenticate user
403 on Graph /meMissing User.Read scopeAdd User.Read to scopes

Reference

Comments

Markdown supported