From 10278d0cc98acad012de1219d151c95e1eaec78f Mon Sep 17 00:00:00 2001 From: Aarnav Tale Date: Mon, 6 Apr 2026 21:36:49 -0400 Subject: [PATCH] fix: correctly expire pre-auth-keys in 0.28.0+ --- app/routes/settings/auth-keys/actions.ts | 11 +++++++---- .../settings/auth-keys/dialogs/expire-auth-key.tsx | 1 + app/server/headscale/api/endpoints/pre-auth-keys.ts | 12 ++++++++++-- tests/integration/api/pre-auth-keys.test.ts | 3 +-- 4 files changed, 19 insertions(+), 8 deletions(-) diff --git a/app/routes/settings/auth-keys/actions.ts b/app/routes/settings/auth-keys/actions.ts index 06d1a14..35ec59c 100644 --- a/app/routes/settings/auth-keys/actions.ts +++ b/app/routes/settings/auth-keys/actions.ts @@ -2,6 +2,7 @@ import { data } from "react-router"; import { getOidcSubject } from "~/server/web/headscale-identity"; import { Capabilities } from "~/server/web/roles"; +import type { PreAuthKey } from "~/types"; import type { Route } from "./+types/overview"; @@ -95,10 +96,12 @@ export async function authKeysAction({ request, context }: Route.ActionArgs) { return data({ success: true as const, key: key.key }); } + case "expire_preauthkey": { + const keyId = formData.get("key_id")?.toString(); const key = formData.get("key")?.toString(); - if (!key) { - return data("Missing `key` in the form data.", { + if (!keyId || !key) { + return data("Missing `key_id` or `key` in the form data.", { status: 400, }); } @@ -111,10 +114,10 @@ export async function authKeysAction({ request, context }: Route.ActionArgs) { } await checkSelfServiceOwnership(user); - - await api.expirePreAuthKey(user, key); + await api.expirePreAuthKey(user, { id: keyId, key } as unknown as PreAuthKey); return data("Pre-auth key expired"); } + default: return data("Invalid action", { status: 400, diff --git a/app/routes/settings/auth-keys/dialogs/expire-auth-key.tsx b/app/routes/settings/auth-keys/dialogs/expire-auth-key.tsx index 01945a6..d53219d 100644 --- a/app/routes/settings/auth-keys/dialogs/expire-auth-key.tsx +++ b/app/routes/settings/auth-keys/dialogs/expire-auth-key.tsx @@ -17,6 +17,7 @@ export default function ExpireAuthKey({ authKey, user }: ExpireAuthKeyProps) { Expire auth key? + Expiring this authentication key will immediately prevent it from being used to diff --git a/app/server/headscale/api/endpoints/pre-auth-keys.ts b/app/server/headscale/api/endpoints/pre-auth-keys.ts index 4fa8bd0..4c6c220 100644 --- a/app/server/headscale/api/endpoints/pre-auth-keys.ts +++ b/app/server/headscale/api/endpoints/pre-auth-keys.ts @@ -34,7 +34,7 @@ export interface PreAuthKeyEndpoints { * @param user The user associated with the pre-authentication key. * @param key The pre-authentication key to expire. */ - expirePreAuthKey(user: string, key: string): Promise; + expirePreAuthKey(user: string, key: PreAuthKey): Promise; } export default defineApiEndpoints((client, apiKey) => ({ @@ -77,9 +77,17 @@ export default defineApiEndpoints((client, apiKey) => ({ }, expirePreAuthKey: async (user, key) => { + if (client.isAtleast("0.28.0")) { + await client.apiFetch("POST", "v1/preauthkey/expire", apiKey, { + id: key.id, + }); + + return; + } + await client.apiFetch("POST", "v1/preauthkey/expire", apiKey, { user, - key, + key: key.key, }); }, })); diff --git a/tests/integration/api/pre-auth-keys.test.ts b/tests/integration/api/pre-auth-keys.test.ts index 53b8e2e..7ce5d0c 100644 --- a/tests/integration/api/pre-auth-keys.test.ts +++ b/tests/integration/api/pre-auth-keys.test.ts @@ -114,8 +114,7 @@ describe.sequential.for(HS_VERSIONS)("Headscale %s: Pre-auth Keys", (version) => const preAuthKeys = await client.getPreAuthKeys(preAuthKeyUser.id); expect(preAuthKeys.length).toBeGreaterThanOrEqual(2); const preAuthKeyToExpire = preAuthKeys[0]; - - await client.expirePreAuthKey(preAuthKeyUser.id, preAuthKeyToExpire.key); + await client.expirePreAuthKey(preAuthKeyUser.id, preAuthKeyToExpire); const preAuthKeysAfterExpire = await client.getPreAuthKeys(preAuthKeyUser.id); const expiredKey = preAuthKeysAfterExpire.find((key) => key.key === preAuthKeyToExpire.key);