get your claude code tokens here
1<!doctype html>
2<html>
3 <head>
4 <meta charset="utf-8" />
5 <meta name="viewport" content="width=device-width, initial-scale=1" />
6 <title>Anthropic Auth</title>
7 <style>
8 body {
9 font-family:
10 system-ui,
11 -apple-system,
12 Segoe UI,
13 Roboto,
14 Ubuntu,
15 Cantarell,
16 Noto Sans,
17 sans-serif;
18 background: #0f0f10;
19 color: #fff;
20 margin: 0;
21 display: flex;
22 min-height: 100vh;
23 align-items: center;
24 justify-content: center;
25 }
26 .card {
27 background: #1a1a1b;
28 border: 1px solid #2b2b2c;
29 border-radius: 14px;
30 padding: 28px;
31 max-width: 560px;
32 width: 100%;
33 }
34 h1 {
35 margin: 0 0 8px;
36 }
37 p {
38 color: #9aa0a6;
39 }
40 button,
41 a.button {
42 background: linear-gradient(135deg, #ff6b35, #ff8e53);
43 color: #fff;
44 border: none;
45 border-radius: 10px;
46 padding: 12px 16px;
47 font-weight: 600;
48 cursor: pointer;
49 text-decoration: none;
50 display: inline-block;
51 }
52 textarea {
53 width: 100%;
54 min-height: 120px;
55 background: #111;
56 border: 1px solid #2b2b2c;
57 border-radius: 10px;
58 color: #fff;
59 padding: 10px;
60 }
61 .row {
62 margin: 16px 0;
63 }
64 .muted {
65 color: #9aa0a6;
66 }
67 .status {
68 margin-top: 8px;
69 font-size: 14px;
70 }
71 </style>
72 </head>
73 <body>
74 <div class="card">
75 <h1>Anthropic Authentication</h1>
76 <p class="muted">
77 Start the OAuth flow, authorize in the new tab, then paste the
78 returned token here.
79 </p>
80
81 <div class="row">
82 <a
83 id="authlink"
84 class="button"
85 href="#"
86 target="_blank"
87 style="display: none"
88 >Open Anthropic Authorization</a
89 >
90 </div>
91
92 <div class="row">
93 <label for="code">Authorization code</label>
94 <textarea
95 id="code"
96 placeholder="Paste the exact code shown by Anthropic (not a URL). If it includes a #, keep the part after it too."
97 ></textarea>
98 </div>
99
100 <div class="row">
101 <button id="complete">Complete Authentication</button>
102 </div>
103
104 <div id="status" class="status"></div>
105 </div>
106
107 <script>
108 let verifier = "";
109 const statusEl = document.getElementById("status");
110
111 function setStatus(msg, ok) {
112 statusEl.textContent = msg;
113 statusEl.style.color = ok ? "#34a853" : "#ea4335";
114 }
115
116 (async () => {
117 setStatus("Preparing authorization...", true);
118 const res = await fetch("/api/auth/start", { method: "POST" });
119 if (!res.ok) {
120 setStatus("Failed to prepare auth", false);
121 return;
122 }
123 const data = await res.json();
124 verifier = data.verifier;
125 const a = document.getElementById("authlink");
126 a.href = data.authUrl;
127 a.style.display = "inline-block";
128 setStatus(
129 'Ready. Click "Open Authorization" to continue.',
130 true,
131 );
132 })();
133
134 const completeBtn = document.getElementById("complete");
135 document
136 .getElementById("complete")
137 .addEventListener("click", async () => {
138 if (completeBtn.disabled) return;
139 completeBtn.disabled = true;
140 const code = document.getElementById("code").value.trim();
141 if (!code || !verifier) {
142 setStatus(
143 "Missing code or verifier. Click Start first.",
144 false,
145 );
146 completeBtn.disabled = false;
147 return;
148 }
149 const res = await fetch("/api/auth/complete", {
150 method: "POST",
151 headers: { "content-type": "application/json" },
152 body: JSON.stringify({ code, verifier }),
153 });
154 if (!res.ok) {
155 setStatus("Code exchange failed", false);
156 completeBtn.disabled = false;
157 return;
158 }
159 setStatus("Authenticated! Fetching token...", true);
160 const t = await fetch("/api/token");
161 if (!t.ok) {
162 setStatus("Could not fetch token", false);
163 completeBtn.disabled = false;
164 return;
165 }
166 const tok = await t.json();
167 setStatus(
168 "Access token acquired (expires " +
169 new Date(tok.expiresAt * 1000).toLocaleString() +
170 ")",
171 true,
172 );
173 setTimeout(() => {
174 try {
175 window.close();
176 } catch {}
177 }, 500);
178 });
179 </script>
180 </body>
181</html>