Download src/app/api/microsoft/devicecode/route.ts from luguog/over: direct link, hf CLI and curl.
- Browser
- Download file 3.87 kB
-
https://huggingface.co/spaces/luguog/over/resolve/main/src/app/api/microsoft/devicecode/route.ts
- Command line
-
hf download hf://spaces/luguog/over/src/app/api/microsoft/devicecode/route.ts
-
curl -L -o route.ts https://huggingface.co/spaces/luguog/over/resolve/main/src/app/api/microsoft/devicecode/route.ts
3.87 kB
| import { NextResponse } from "next/server"; | |
| import { loadConfig } from "@/lib/config"; | |
| export const dynamic = "force-dynamic"; | |
| export const maxDuration = 10; | |
| const UUID_REGEX = /^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/; | |
| const MISSING_CONFIG_ERROR = | |
| "Microsoft OAuth is not configured. The built-in Azure CLI client ID can no longer be used because Microsoft treats it as a first-party application and requires admin pre-authorization. " + | |
| "To connect a Microsoft 365 mailbox, register your own Azure AD application and set AZURE_AD_CLIENT_ID (or AZURE_CLIENT_ID / MICROSOFT_CLIENT_ID) and AZURE_AD_TENANT_ID (or 'common'). " + | |
| "See the README for step-by-step registration instructions."; | |
| /** | |
| * POST /api/microsoft/devicecode | |
| * | |
| * Initiates the OAuth device code flow for Microsoft 365 / Outlook. | |
| * Uses the Azure AD client ID configured via environment variables or the | |
| * app config file. A dedicated app registration is required because the Azure | |
| * CLI client ID is a first-party application that Microsoft no longer allows | |
| * users to consent to directly. | |
| * | |
| * Returns: | |
| * device_code: string β internal code for polling | |
| * user_code: string β code the user enters at the verification URI | |
| * verification_uri: string β URL the user visits to login | |
| * expires_in: number β seconds until the code expires | |
| * interval: number β polling interval in seconds | |
| * message: string β human-readable instructions | |
| */ | |
| export async function POST() { | |
| let config; | |
| try { | |
| config = loadConfig(); | |
| } catch (e) { | |
| console.error("[microsoft/devicecode] loadConfig error:", e); | |
| config = { graph: {} }; | |
| } | |
| const CLIENT_ID = | |
| process.env.AZURE_AD_CLIENT_ID || | |
| process.env.AZURE_CLIENT_ID || | |
| process.env.MICROSOFT_CLIENT_ID || | |
| config.graph?.clientId || | |
| ""; | |
| const TENANT = | |
| process.env.AZURE_AD_TENANT_ID || | |
| process.env.AZURE_TENANT_ID || | |
| process.env.MICROSOFT_TENANT_ID || | |
| config.graph?.tenantId || | |
| "common"; | |
| if (!CLIENT_ID || !UUID_REGEX.test(CLIENT_ID)) { | |
| return NextResponse.json({ error: MISSING_CONFIG_ERROR }, { status: 400 }); | |
| } | |
| const SCOPES = [ | |
| "https://graph.microsoft.com/Mail.Read", | |
| "https://graph.microsoft.com/Mail.ReadWrite", | |
| "https://graph.microsoft.com/Files.Read", | |
| "https://graph.microsoft.com/Files.Read.All", | |
| "offline_access", | |
| "openid", | |
| "profile", | |
| ]; | |
| try { | |
| const controller = new AbortController(); | |
| const timeout = setTimeout(() => controller.abort(), 9000); | |
| try { | |
| const res = await fetch( | |
| `https://login.microsoftonline.com/${TENANT}/oauth2/v2.0/devicecode`, | |
| { | |
| method: "POST", | |
| headers: { "Content-Type": "application/x-www-form-urlencoded" }, | |
| body: new URLSearchParams({ | |
| client_id: CLIENT_ID, | |
| scope: SCOPES.join(" "), | |
| }), | |
| signal: controller.signal, | |
| } | |
| ); | |
| const text = await res.text(); | |
| const data = text ? JSON.parse(text) : {}; | |
| if (!res.ok) { | |
| return NextResponse.json( | |
| { error: data.error_description || data.error || "Failed to start device code flow" }, | |
| { status: 500 } | |
| ); | |
| } | |
| return NextResponse.json({ | |
| device_code: data.device_code, | |
| user_code: data.user_code, | |
| verification_uri: data.verification_uri, | |
| expires_in: data.expires_in, | |
| interval: data.interval || 5, | |
| message: data.message || `Go to ${data.verification_uri} and enter code ${data.user_code}`, | |
| client_id: CLIENT_ID, | |
| tenant_id: TENANT, | |
| scopes: SCOPES, | |
| }); | |
| } finally { | |
| clearTimeout(timeout); | |
| } | |
| } catch (e: any) { | |
| return NextResponse.json({ error: e.name === "AbortError" ? "Device code request timed out" : e.message }, { status: 504 }); | |
| } | |
| } | |