GitHub OAuth
OAuth authentication for Express using GitHub — includes secure JWT issuance and user profile handling with TypeScript support.
Overview
A flexible OAuth authentication component for Express.js using GitHub as the provider. It handles the full flow — authorization redirect, token exchange, profile retrieval, and JWT issuance. Ideal for adding “Login with GitHub” functionality to any backend or Next.js app.
Installation
What This Does
Installs a TypeScript-based GitHub OAuth 2.0 authentication flow with automatic JWT generation and user profile management.
Files & Folders Created
| File / Path | Description |
|---|---|
| /src/routes/oauth.ts | Defines GitHub OAuth endpoints. |
| /src/controllers/oauthController.ts | Handles GitHub OAuth logic and callback processing. |
| /src/services/oauthService.ts | Manages token exchange, user retrieval, and JWT creation. |
| /src/models/OAuthUser.ts | Defines a typed in-memory user model. |
| /.env.example | Includes JWT, app, and GitHub credentials. |
Files to be modified
| File / Path | Description |
|---|---|
| server.ts | Mounts /api/oauth routes. |
| tsconfig.json | (optional) Ensures module resolution for @/ imports. |
Configuration
# JWT Configuration JWT_SECRET=your-super-secret-key JWT_EXPIRES_IN=7d # Application Settings APP_URL=http://localhost:3000 PORT=3000 # GitHub OAuth GITHUB_CLIENT_ID=your-github-client-id GITHUB_CLIENT_SECRET=your-github-client-secret GITHUB_REDIRECT_URI=http://localhost:3000/api/oauth/github/callback
Frontend Integration
Below is a complete **Next.js** example that demonstrates GitHub OAuth login. After successful authentication, the backend returns a signed JWT and user profile.
Redirects the user to GitHub for authorization.
Handles GitHub's callback, issues JWT, and returns the user profile.
Example
1// app/components/GitHubLogin.jsx
2'use client';
3import { useState, useEffect } from 'react';
4
5export default function GitHubLogin() {
6 const [user, setUser] = useState(null);
7 const [message, setMessage] = useState('');
8
9 useEffect(() => {
10 // Handle redirect after GitHub callback
11 const params = new URLSearchParams(window.location.search);
12 const token = params.get('token');
13 if (token) {
14 localStorage.setItem('accessToken', token);
15 fetchUser(token);
16 }
17 }, []);
18
19 async function fetchUser(token) {
20 try {
21 const res = await fetch('/api/auth/me', {
22 headers: { Authorization: 'Bearer ' + token },
23 });
24 const data = await res.json();
25 setUser(data.user);
26 } catch {
27 setMessage('Failed to fetch user profile.');
28 }
29 }
30
31 function handleGitHubLogin() {
32 window.location.href = '/api/oauth/github';
33 }
34
35 return (
36 <div className="max-w-sm mx-auto bg-black/20 border border-white/10 rounded-xl p-6 text-white space-y-4">
37 <h2 className="text-xl font-semibold">Login with GitHub</h2>
38
39 {!user && (
40 <button
41 onClick={handleGitHubLogin}
42 className="w-full bg-gray-800 hover:bg-gray-700 text-white font-semibold py-2 rounded-md transition-colors"
43 >
44 Continue with GitHub
45 </button>
46 )}
47
48 {user && (
49 <div className="p-3 bg-emerald-500/10 rounded-lg border border-emerald-500/20">
50 <p className="text-sm text-emerald-300">✅ Logged in as {user.name}</p>
51 <p className="text-xs text-white/70 mt-1">{user.email}</p>
52 <p className="text-xs text-white/70 mt-1">
53 GitHub ID: {user.oauthId}
54 </p>
55 </div>
56 )}
57
58 {message && <p className="text-amber-400 text-sm">{message}</p>}
59 </div>
60 );
61}Usage
1// Example of protecting a route with the returned JWT
2import express from 'express';
3import jwt from 'jsonwebtoken';
4
5const app = express();
6
7function validateAuth(req, res, next) {
8 const header = req.headers.authorization;
9 if (!header?.startsWith('Bearer '))
10 return res.status(401).json({ error: 'Missing token' });
11 try {
12 const token = header.split(' ')[1];
13 req.user = jwt.verify(token, process.env.JWT_SECRET);
14 next();
15 } catch {
16 res.status(401).json({ error: 'Invalid token' });
17 }
18}
19
20app.get('/api/protected', validateAuth, (req, res) => {
21 res.json({ message: 'Access granted', user: req.user });
22});