fix: send browser origin for passkey options
This commit is contained in:
parent
28304f13c3
commit
cd6468bb92
|
|
@ -2507,6 +2507,8 @@ struct PasskeyRegistrationOptionsRequest {
|
||||||
handle: String,
|
handle: String,
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
display_name: Option<String>,
|
display_name: Option<String>,
|
||||||
|
#[serde(default)]
|
||||||
|
browser_origin: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
|
|
@ -2527,6 +2529,8 @@ struct PasskeyRegistrationCompleteRequest {
|
||||||
struct PasskeyLoginOptionsRequest {
|
struct PasskeyLoginOptionsRequest {
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
handle: Option<String>,
|
handle: Option<String>,
|
||||||
|
#[serde(default)]
|
||||||
|
browser_origin: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
|
|
@ -2619,7 +2623,12 @@ async fn post_passkey_registration_options(
|
||||||
Json(request): Json<PasskeyRegistrationOptionsRequest>,
|
Json(request): Json<PasskeyRegistrationOptionsRequest>,
|
||||||
) -> ApiResult<Json<PasskeyRegistrationOptionsResponse>> {
|
) -> ApiResult<Json<PasskeyRegistrationOptionsResponse>> {
|
||||||
let user = ensure_user_account(&api, &request.handle, request.display_name.as_deref())?;
|
let user = ensure_user_account(&api, &request.handle, request.display_name.as_deref())?;
|
||||||
let auth = auth_config_for_origin(&api.config, request_origin(&headers).as_deref())?;
|
let header_origin = request_origin(&headers);
|
||||||
|
let requested_origin = request
|
||||||
|
.browser_origin
|
||||||
|
.as_deref()
|
||||||
|
.or(header_origin.as_deref());
|
||||||
|
let auth = auth_config_for_origin(&api.config, requested_origin)?;
|
||||||
let webauthn = webauthn_for_auth(&auth)?;
|
let webauthn = webauthn_for_auth(&auth)?;
|
||||||
let exclude_credentials = passkeys_for_user(&api, &user.user_id)?
|
let exclude_credentials = passkeys_for_user(&api, &user.user_id)?
|
||||||
.into_iter()
|
.into_iter()
|
||||||
|
|
@ -2746,7 +2755,12 @@ async fn post_passkey_login_options(
|
||||||
)
|
)
|
||||||
.into());
|
.into());
|
||||||
}
|
}
|
||||||
let auth = auth_config_for_origin(&api.config, request_origin(&headers).as_deref())?;
|
let header_origin = request_origin(&headers);
|
||||||
|
let requested_origin = request
|
||||||
|
.browser_origin
|
||||||
|
.as_deref()
|
||||||
|
.or(header_origin.as_deref());
|
||||||
|
let auth = auth_config_for_origin(&api.config, requested_origin)?;
|
||||||
let webauthn = webauthn_for_auth(&auth)?;
|
let webauthn = webauthn_for_auth(&auth)?;
|
||||||
let (public_key, state) = webauthn
|
let (public_key, state) = webauthn
|
||||||
.start_passkey_authentication(&passkeys)
|
.start_passkey_authentication(&passkeys)
|
||||||
|
|
@ -3087,9 +3101,17 @@ fn auth_config_for_origin(
|
||||||
"request Origin header does not contain a host",
|
"request Origin header does not contain a host",
|
||||||
)
|
)
|
||||||
})?;
|
})?;
|
||||||
if host == auth.rp_id {
|
if host != auth.rp_id {
|
||||||
auth.origin = request_origin.to_string();
|
return Err(auth_error(
|
||||||
|
"webauthn_origin_rp_id_mismatch",
|
||||||
|
&format!(
|
||||||
|
"browser origin host {host} does not match configured RP ID {}",
|
||||||
|
auth.rp_id
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.into());
|
||||||
}
|
}
|
||||||
|
auth.origin = request_origin.to_string();
|
||||||
Ok(auth)
|
Ok(auth)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,10 @@ async function jsonOrThrow<T>(response: Response): Promise<T> {
|
||||||
return text ? JSON.parse(text) as T : (null as T);
|
return text ? JSON.parse(text) as T : (null as T);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function browserOrigin(): string | null {
|
||||||
|
return globalThis.location?.origin ?? null;
|
||||||
|
}
|
||||||
|
|
||||||
export async function loadWhoami(fetcher: typeof fetch = fetch): Promise<WhoamiResponse> {
|
export async function loadWhoami(fetcher: typeof fetch = fetch): Promise<WhoamiResponse> {
|
||||||
return await fetcher("/api/auth/whoami", { credentials: "same-origin" }).then(jsonOrThrow<WhoamiResponse>);
|
return await fetcher("/api/auth/whoami", { credentials: "same-origin" }).then(jsonOrThrow<WhoamiResponse>);
|
||||||
}
|
}
|
||||||
|
|
@ -32,7 +36,7 @@ export async function registerPasskey(
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: { "content-type": "application/json" },
|
headers: { "content-type": "application/json" },
|
||||||
credentials: "same-origin",
|
credentials: "same-origin",
|
||||||
body: JSON.stringify({ handle, display_name: displayName }),
|
body: JSON.stringify({ handle, display_name: displayName, browser_origin: browserOrigin() }),
|
||||||
}).then(jsonOrThrow<PasskeyRegistrationOptionsResponse>);
|
}).then(jsonOrThrow<PasskeyRegistrationOptionsResponse>);
|
||||||
|
|
||||||
const credential = await navigator.credentials.create({
|
const credential = await navigator.credentials.create({
|
||||||
|
|
@ -61,7 +65,7 @@ export async function loginWithPasskey(
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: { "content-type": "application/json" },
|
headers: { "content-type": "application/json" },
|
||||||
credentials: "same-origin",
|
credentials: "same-origin",
|
||||||
body: JSON.stringify({ handle }),
|
body: JSON.stringify({ handle, browser_origin: browserOrigin() }),
|
||||||
}).then(jsonOrThrow<PasskeyLoginOptionsResponse>);
|
}).then(jsonOrThrow<PasskeyLoginOptionsResponse>);
|
||||||
|
|
||||||
const credential = await navigator.credentials.get({
|
const credential = await navigator.credentials.get({
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user