fix(auth): add user billing dependency spans (#1948)

This commit is contained in:
Lyon
2026-06-23 04:36:19 +08:00
committed by GitHub
parent 7562dc3276
commit 5000842320
+62 -5
View File
@@ -599,8 +599,56 @@ class AccessController {
return { ok: true, actor: session.user, session: publicSession(session), authMethod: AUTH_METHOD_WEB_SESSION };
}
async authenticateUserBillingToken(secret) {
const result = await this.userBilling.introspect(secret);
async withAuthOtelDependencySpan(name, otelContext, parentSpanId, attributes, fn, classifyResult = null) {
const spanId = otelContext ? newOtelSpanId() : "";
const startedAtMs = Date.now();
let statusCode = 0;
let errorCode = "";
try {
const result = await fn();
const classified = typeof classifyResult === "function" ? classifyResult(result) : null;
statusCode = Number(classified?.statusCode ?? 0);
errorCode = textOr(classified?.errorCode, "");
return result;
} catch (error) {
statusCode = Number(error?.statusCode ?? error?.status ?? 503);
errorCode = textOr(error?.code, `${name.replace(/[^A-Za-z0-9]+/g, "_")}_exception`);
throw error;
} finally {
if (otelContext) {
void emitAuthOtelSpan(name, otelContext, this.env, {
spanId,
parentSpanId: parentSpanId || otelContext.rootSpanId,
kind: 3,
startTimeMs: startedAtMs,
endTimeMs: Date.now(),
status: errorCode ? "error" : "ok",
error: errorCode ? new Error(errorCode) : null,
attributes: {
...attributes,
...(statusCode > 0 ? { "http.status_code": statusCode } : {}),
...(errorCode ? { "error.code": errorCode } : {}),
"auth.trace_visible": true,
"auth.values_redacted": true
}
});
}
}
}
async authenticateUserBillingToken(secret, otel = null) {
const otelContext = otel?.context ?? null;
const parentSpanId = textOr(otel?.parentSpanId, "");
const result = await this.withAuthOtelDependencySpan("auth.user_billing.introspect", otelContext, parentSpanId, {
"http.method": "POST",
"http.route": "/internal/auth/introspect",
"server.address": "hwlab-user-billing",
"user_billing.service_id": "hwlab-user-billing",
"user_billing.operation": "introspect"
}, () => this.userBilling.introspect(secret), (item) => ({
statusCode: Number(item?.status ?? 0),
errorCode: item?.ok ? "" : textOr(item?.error?.code, "user_billing_introspect_failed")
}));
if (!result.ok) {
return errorPayload(result.error?.code ?? "user_billing_introspect_failed", result.error?.message ?? "user-billing introspection failed", result.status ?? 503);
}
@@ -609,7 +657,11 @@ class AccessController {
}
const principal = result.body.principal;
const actor = userBillingActor(principal);
const synced = await this.store.upsertExternalUser?.({ ...actor, authProvider: "user-billing", email: principal.email, now: this.now() }) ?? actor;
const synced = await this.withAuthOtelDependencySpan("auth.local.upsert_external_user", otelContext, parentSpanId, {
"db.system": "postgresql",
"db.sql.table": "users",
"auth.operation": "upsert_external_user"
}, async () => await this.store.upsertExternalUser?.({ ...actor, authProvider: "user-billing", email: principal.email, now: this.now() }) ?? actor);
const authMethod = principal.authType === "session" ? AUTH_METHOD_USER_BILLING_SESSION : AUTH_METHOD_USER_BILLING_API_KEY;
return {
ok: true,
@@ -944,11 +996,16 @@ class AccessController {
};
}
const upstreamToken = textOr(login.body.token, "");
const auth = await this.authenticateUserBillingToken(upstreamToken);
const auth = await this.authenticateUserBillingToken(upstreamToken, otelContext ? { context: otelContext, parentSpanId: spanId } : null);
if (!auth.ok) {
thrownCode = textOr(auth?.error?.code, "user_billing_introspect_failed");
return { ok: false, status: auth.status, error: auth.error };
}
const localSession = await this.issueWebSessionForActor(auth.actor);
const localSession = await this.withAuthOtelDependencySpan("auth.local.issue_web_session", otelContext, spanId, {
"db.system": "postgresql",
"db.sql.table": "sessions",
"auth.operation": "issue_web_session"
}, () => this.issueWebSessionForActor(auth.actor));
const localAuth = {
ok: true,
actor: auth.actor,