File size: 2,086 Bytes
eeb9404
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
import { NextRequest, NextResponse } from 'next/server';
import { CODEX_COOKIE_NAME, codexCookieOptions } from '../cookie';

const CLIENT_ID = 'app_EMoamEEZ73f0CkXaXp7hrann';

/**
 * Refreshes the Codex access token using the refresh_token stored in the
 * HttpOnly cookie. The client never sees or sends the refresh_token.
 */
export async function POST(request: NextRequest) {
  try {
    const refreshToken = request.cookies.get(CODEX_COOKIE_NAME)?.value;

    if (!refreshToken) {
      return NextResponse.json(
        { error: 'No refresh token cookie. Please re-authenticate.' },
        { status: 401 },
      );
    }

    const formBody = new URLSearchParams({
      grant_type: 'refresh_token',
      client_id: CLIENT_ID,
      refresh_token: refreshToken,
    });

    const res = await fetch('https://auth.openai.com/oauth/token', {
      method: 'POST',
      headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
      body: formBody.toString(),
    });

    const data = await res.json();

    if (!res.ok) {
      // If the refresh token is revoked/expired, clear the cookie
      if (res.status === 401 || res.status === 403) {
        const errResponse = NextResponse.json(
          { error: data.error_description || 'Refresh token revoked' },
          { status: 401 },
        );
        errResponse.cookies.set(CODEX_COOKIE_NAME, '', codexCookieOptions(0));
        return errResponse;
      }
      return NextResponse.json(data, { status: res.status });
    }

    const response = NextResponse.json({
      access_token: data.access_token,
      expires_at: Math.floor(Date.now() / 1000) + (data.expires_in || 3600),
    });

    // If OpenAI rotated the refresh token, update the cookie
    if (data.refresh_token && data.refresh_token !== refreshToken) {
      response.cookies.set(CODEX_COOKIE_NAME, data.refresh_token, codexCookieOptions());
    }

    return response;
  } catch (error) {
    const message = error instanceof Error ? error.message : 'Unknown error';
    return NextResponse.json({ error: message }, { status: 500 });
  }
}