Skip to main content
Glama
hiltonbrown

Next.js MCP Server Template

by hiltonbrown
route.ts3.23 kB
// Maintenance route for refreshing expired OAuth tokens import { NextRequest, NextResponse } from 'next/server'; import { db } from '@/lib/db'; import { refreshAccessToken } from '@/lib/auth'; // Import encryption utilities const ENCRYPTION_KEY = process.env.ENCRYPTION_KEY || 'default-key-change-in-production'; function encrypt(text: string): string { const crypto = require('crypto'); const iv = crypto.randomBytes(16); const cipher = crypto.createCipheriv('aes-256-cbc', Buffer.from(ENCRYPTION_KEY), iv); let encrypted = cipher.update(text, 'utf8', 'hex'); encrypted += cipher.final('hex'); return iv.toString('hex') + ':' + encrypted; } function decrypt(encryptedText: string): string { const crypto = require('crypto'); const [ivHex, encrypted] = encryptedText.split(':'); const iv = Buffer.from(ivHex, 'hex'); const decipher = crypto.createDecipheriv('aes-256-cbc', Buffer.from(ENCRYPTION_KEY), iv); let decrypted = decipher.update(encrypted, 'hex', 'utf8'); decrypted += decipher.final('utf8'); return decrypted; } export async function GET(request: NextRequest) { try { // Find tokens that will expire in the next hour const oneHourFromNow = new Date(Date.now() + 60 * 60 * 1000); const expiringTokens = await db.oAuthToken.findMany({ where: { expiresAt: { lt: oneHourFromNow, gt: new Date() // Not already expired } }, include: { account: true } }); let refreshedCount = 0; let failedCount = 0; for (const token of expiringTokens) { try { // Attempt to refresh the token const refreshToken = decryptToken(token.refreshToken); const newTokens = await refreshAccessToken(refreshToken); // Update the token in database const encryptedAccessToken = encrypt(newTokens.access_token); const encryptedRefreshToken = encrypt(newTokens.refresh_token); const expiresAt = new Date(Date.now() + newTokens.expires_in * 1000); await db.oAuthToken.update({ where: { id: token.id }, data: { accessToken: encryptedAccessToken, refreshToken: encryptedRefreshToken, expiresAt, updatedAt: new Date() } }); refreshedCount++; } catch (error) { console.error(`Failed to refresh token for account ${token.accountId}:`, error); failedCount++; // If refresh fails, mark token as expired by setting expiresAt to past await db.oAuthToken.update({ where: { id: token.id }, data: { expiresAt: new Date(Date.now() - 1000), // Set to past updatedAt: new Date() } }); } } return NextResponse.json({ success: true, refreshed: refreshedCount, failed: failedCount, total: expiringTokens.length }); } catch (error) { console.error('Token refresh maintenance error:', error); return NextResponse.json( { error: 'Failed to refresh tokens' }, { status: 500 } ); } } // Helper function to decrypt tokens function decryptToken(encryptedToken: string): string { return decrypt(encryptedToken); }

Latest Blog Posts

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/hiltonbrown/xero-mcp-with-next-js'

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