Skip to content

Commit 0e2856c

Browse files
committed
Add API key expiry support
1 parent 1b53bb5 commit 0e2856c

2 files changed

Lines changed: 26 additions & 2 deletions

File tree

apps/web/src/components/dashboard/ApiKeyManager.tsx

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,17 +17,19 @@ export default function ApiKeyManager() {
1717
const { openPaywall } = usePaywall()
1818

1919
const [newKeyName, setNewKeyName] = useState('')
20+
const [expiresIn, setExpiresIn] = useState<number | null>(null)
2021
const [showCreate, setShowCreate] = useState(false)
2122
const [newKeyValue, setNewKeyValue] = useState<string | null>(null)
2223

2324
function handleCreate(e: React.FormEvent<HTMLFormElement>) {
2425
e.preventDefault()
25-
createKey.mutate(newKeyName.trim() || undefined, {
26+
createKey.mutate({ name: newKeyName.trim() || undefined, expiresIn }, {
2627
onSuccess: (data) => {
2728
if (data?.key) {
2829
setNewKeyValue(data.key)
2930
}
3031
setNewKeyName('')
32+
setExpiresIn(null)
3133
},
3234
onError: (err) => {
3335
if (err instanceof ApiError && err.status === 403) {
@@ -111,6 +113,22 @@ export default function ApiKeyManager() {
111113
className="dash-input"
112114
disabled={createKey.isPending}
113115
/>
116+
<label htmlFor="key-expiry" className="dash-label">
117+
Expiry
118+
</label>
119+
<select
120+
id="key-expiry"
121+
className="dash-select"
122+
value={expiresIn ?? ''}
123+
onChange={(e) => setExpiresIn(e.target.value ? Number(e.target.value) : null)}
124+
disabled={createKey.isPending}
125+
>
126+
<option value="">No expiry</option>
127+
<option value="604800">7 days</option>
128+
<option value="2592000">30 days</option>
129+
<option value="5184000">60 days</option>
130+
<option value="7776000">90 days</option>
131+
</select>
114132
<button
115133
type="submit"
116134
className="dash-primary-btn"
@@ -130,6 +148,7 @@ export default function ApiKeyManager() {
130148
<tr>
131149
<th>Name</th>
132150
<th>Key</th>
151+
<th>Expires</th>
133152
<th>Created</th>
134153
<th scope="col"><span className="sr-only">Actions</span></th>
135154
</tr>
@@ -143,6 +162,9 @@ export default function ApiKeyManager() {
143162
<td>
144163
<code className="dash-key-prefix">{key.start ?? '???'}...</code>
145164
</td>
165+
<td className="dash-text-weak">
166+
{key.expiresAt ? formatShortDate(key.expiresAt) : 'Never'}
167+
</td>
146168
<td className="dash-text-weak">{formatShortDate(key.createdAt)}</td>
147169
<td>
148170
<button

apps/web/src/hooks/use-api-keys.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ interface ApiKey {
77
id: string
88
name: string | null
99
start: string | null
10+
expiresAt: Date | null
1011
createdAt: Date
1112
}
1213

@@ -30,9 +31,10 @@ export function useCreateApiKey() {
3031
const queryClient = useQueryClient()
3132

3233
return useMutation({
33-
mutationFn: async (name: string | undefined) => {
34+
mutationFn: async ({ name, expiresIn }: { name?: string | undefined; expiresIn?: number | null }) => {
3435
const { data, error } = await authClient.apiKey.create({
3536
name: name || undefined,
37+
...(expiresIn != null ? { expiresIn } : {}),
3638
})
3739
if (error) throw new Error(error.message ?? 'Failed to create API key')
3840
return data as { key: string } | null

0 commit comments

Comments
 (0)