mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-15 15:02:04 +00:00
feat(claim): hand over a managed profile through single sign-on
POST /api/auth/claim/sso checks the handover link and the username and seals the link id, the username and a per-start binding into an hl_claim cookie. GET /api/auth/oidc/login?intent=claim carries the binding into the encrypted OIDC state, and the callback binds the provider subject to the profile in the claim transaction, refusing a subject or verified email another account holds, a link that is no longer usable, and a live session. The handover status and the claim preview name the redemption methods; a single-sign-on-only server hands over through the identity provider, and only the password claim stays refused there.
This commit is contained in:
1 parent
5dab12472f
commit
9eae352bb1
20 files changed
+1075
-208
No files matched your search
@@ -30,8 +30,8 @@ import {
|
||||
safeJson,
|
||||
} from "@/lib/api-response";
|
||||
import { buildHandoverUrl } from "@/lib/auth/handover-token";
|
||||
import { isOidcOnly } from "@/lib/auth/oidc";
|
||||
import { annotate } from "@/lib/logging/context";
|
||||
import { handoverMethods } from "@/lib/managed-profiles/claim-gate";
|
||||
import {
|
||||
createHandover,
|
||||
HandoverError,
|
||||
@@ -49,16 +49,15 @@ const notFound = () =>
|
||||
});
|
||||
|
||||
/**
|
||||
* v1.42 refuses the handover on a single-sign-on-only instance: the claim
|
||||
* sets a password, and such an instance admits none. The SSO arm of the claim
|
||||
* is a separate piece of work.
|
||||
* A link nobody could redeem is not minted. Since v1.43 the person can claim
|
||||
* through the identity provider, so a single-sign-on-only server hands over
|
||||
* too; this answers only when neither a password nor single sign-on is
|
||||
* possible, which a working configuration never produces.
|
||||
*/
|
||||
const oidcOnlyRefusal = () =>
|
||||
apiError(
|
||||
"Handing over a profile is not available while this server allows single sign-on only",
|
||||
403,
|
||||
{ errorCode: "profile_claim.oidc_only_unsupported" },
|
||||
);
|
||||
const noMethodRefusal = () =>
|
||||
apiError("Handing over a profile is not available on this server", 403, {
|
||||
errorCode: "profile_claim.oidc_only_unsupported",
|
||||
});
|
||||
|
||||
/** Same ceiling as creating, editing and inviting: ten an hour per caller. */
|
||||
const CREATE_LIMIT = 10;
|
||||
@@ -79,8 +78,10 @@ export const GET = apiHandler(
|
||||
action: { name: "managed_profile.handover.read" },
|
||||
meta: { profile_id: id, open: status.open !== null },
|
||||
});
|
||||
const methods = handoverMethods();
|
||||
return apiSuccess({
|
||||
available: !isOidcOnly(),
|
||||
available: methods.length > 0,
|
||||
methods,
|
||||
open: status.open
|
||||
? {
|
||||
id: status.open.id,
|
||||
@@ -107,7 +108,7 @@ export const POST = apiHandler(
|
||||
if (!rateLimit.allowed) {
|
||||
return apiError("Too many handover links, try again later", 429);
|
||||
}
|
||||
if (isOidcOnly()) return oidcOnlyRefusal();
|
||||
if (handoverMethods().length === 0) return noMethodRefusal();
|
||||
const { id } = await params;
|
||||
|
||||
const { data: body, error: jsonError } = await safeJson(request, {
|
||||
|
||||
Reference in new issue
Block a user