Skip to main content
Glama

Weather MCP Server with GitHub OAuth & Location Management

by f
auth.js•5.41 kB
import { getUserByAccessToken, upsertOAuthUser } from './database.js'; import dotenv from 'dotenv'; dotenv.config(); /** * Middleware to authenticate requests using Bearer token (OAuth) */ export async function authenticateRequest(req, res, next) { try { const authHeader = req.headers.authorization; if (!authHeader) { return res.status(401).json({ error: 'Authorization header required', message: 'Please provide a valid OAuth access token in the Authorization header', }); } // Extract Bearer token const parts = authHeader.split(' '); if (parts.length !== 2 || parts[0] !== 'Bearer') { return res.status(401).json({ error: 'Invalid authorization header format', message: 'Authorization header must be in format: Bearer <token>', }); } const accessToken = parts[1]; // Verify token and get user from database const user = getUserByAccessToken(accessToken); if (!user) { return res.status(401).json({ error: 'Invalid access token', message: 'The provided access token is not valid or has expired', }); } // Check if token is expired if (user.token_expires_at && new Date(user.token_expires_at) < new Date()) { return res.status(401).json({ error: 'Token expired', message: 'The access token has expired. Please re-authenticate.', }); } // Attach user to request object req.user = { id: user.id, github_id: user.github_id, username: user.github_username, email: user.github_email, name: user.name, avatar_url: user.avatar_url, }; next(); } catch (error) { console.error('[AUTH] Error during authentication:', error); return res.status(500).json({ error: 'Authentication error', message: 'An error occurred during authentication', }); } } /** * GitHub OAuth callback handler * Exchanges authorization code for access token and creates/updates user */ export async function handleGitHubCallback(code) { try { const clientId = process.env.GITHUB_CLIENT_ID; const clientSecret = process.env.GITHUB_CLIENT_SECRET; const redirectUri = process.env.GITHUB_REDIRECT_URI || 'http://localhost:3000/oauth/callback'; if (!clientId || !clientSecret) { throw new Error('GitHub OAuth credentials not configured'); } // Exchange code for access token const tokenResponse = await fetch('https://github.com/login/oauth/access_token', { method: 'POST', headers: { 'Content-Type': 'application/json', 'Accept': 'application/json', }, body: JSON.stringify({ client_id: clientId, client_secret: clientSecret, code, redirect_uri: redirectUri, }), }); const tokenData = await tokenResponse.json(); if (tokenData.error) { throw new Error(`GitHub OAuth error: ${tokenData.error_description || tokenData.error}`); } const accessToken = tokenData.access_token; const refreshToken = tokenData.refresh_token; const expiresIn = tokenData.expires_in; // Get user information from GitHub const userResponse = await fetch('https://api.github.com/user', { headers: { 'Authorization': `Bearer ${accessToken}`, 'Accept': 'application/vnd.github.v3+json', }, }); const githubUser = await userResponse.json(); if (!userResponse.ok) { throw new Error(`Failed to fetch GitHub user: ${githubUser.message}`); } // Get user email if not public let email = githubUser.email; if (!email) { const emailResponse = await fetch('https://api.github.com/user/emails', { headers: { 'Authorization': `Bearer ${accessToken}`, 'Accept': 'application/vnd.github.v3+json', }, }); const emails = await emailResponse.json(); const primaryEmail = emails.find(e => e.primary) || emails[0]; email = primaryEmail?.email; } // Calculate token expiration const tokenExpiresAt = expiresIn ? new Date(Date.now() + expiresIn * 1000).toISOString() : null; // Create or update user in database const user = upsertOAuthUser(githubUser.id.toString(), { username: githubUser.login, email, name: githubUser.name || githubUser.login, avatar_url: githubUser.avatar_url, access_token: accessToken, refresh_token: refreshToken, token_expires_at: tokenExpiresAt, }); return { success: true, user: { id: user.id, github_id: user.github_id, username: user.github_username, email: user.github_email, name: user.name, avatar_url: user.avatar_url, }, access_token: accessToken, }; } catch (error) { console.error('[AUTH] GitHub OAuth error:', error); throw error; } } /** * Generate GitHub OAuth authorization URL */ export function getGitHubAuthUrl(state) { const clientId = process.env.GITHUB_CLIENT_ID; const redirectUri = process.env.GITHUB_REDIRECT_URI || 'http://localhost:3000/oauth/callback'; const scope = 'read:user user:email'; const params = new URLSearchParams({ client_id: clientId, redirect_uri: redirectUri, scope, state, }); return `https://github.com/login/oauth/authorize?${params.toString()}`; }

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/f/komunite-mcp-bootcamp-weather-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server