Update WebAuthn registration and authentication to use new and safer impl (#5)
* Update WebAuthn registration and authentication to use new and safer flow * Implement usernameless WebAuthn registration + Authentication The username is solely stored in the client side for the end-user to conveniently refer to. * Use updated SDK interface * Implement executeJs in webauthn demo * Show executeJs sig * Fix username bug * encodeURIComponent for username * Use latest working SDK version * Use serrano
This commit is contained in:
parent
efb3eab092
commit
2e19c39625
11
package.json
11
package.json
@ -5,11 +5,12 @@
|
||||
"dependencies": {
|
||||
"@emotion/react": "^11.10.5",
|
||||
"@emotion/styled": "^11.10.5",
|
||||
"@lit-protocol/access-control-conditions": "2.1.17",
|
||||
"@lit-protocol/bls-sdk": "2.1.17",
|
||||
"@lit-protocol/constants": "2.1.17",
|
||||
"@lit-protocol/crypto": "2.1.17",
|
||||
"@lit-protocol/lit-node-client": "2.1.17",
|
||||
"@lit-protocol/access-control-conditions": "2.1.111",
|
||||
"@lit-protocol/bls-sdk": "2.1.111",
|
||||
"@lit-protocol/constants": "2.1.111",
|
||||
"@lit-protocol/crypto": "2.1.111",
|
||||
"@lit-protocol/lit-node-client": "2.1.111",
|
||||
"@lit-protocol/lit-node-client-nodejs": "2.1.111",
|
||||
"@mui/material": "^5.10.16",
|
||||
"@react-oauth/google": "^0.4.0",
|
||||
"@simplewebauthn/browser": "^6.2.2",
|
||||
|
449
src/App.tsx
449
src/App.tsx
@ -1,20 +1,18 @@
|
||||
import * as LitJsSdk_accessControlConditions from "@lit-protocol/access-control-conditions";
|
||||
import * as LitJsSdk_blsSdk from "@lit-protocol/bls-sdk";
|
||||
import { AccsDefaultParams } from "@lit-protocol/constants";
|
||||
import * as LitJsSdk from "@lit-protocol/lit-node-client";
|
||||
import { Button, ButtonGroup } from "@mui/material";
|
||||
import { AccsDefaultParams, JsonAuthSig } from "@lit-protocol/types";
|
||||
import { Button, ButtonGroup, TextField } from "@mui/material";
|
||||
import { GoogleLogin } from "@react-oauth/google";
|
||||
import {
|
||||
startAuthentication,
|
||||
startRegistration,
|
||||
} from "@simplewebauthn/browser";
|
||||
import base64url from "base64url";
|
||||
import { utils } from "ethers";
|
||||
import { hexlify } from "ethers/lib/utils";
|
||||
import { ethers, utils } from "ethers";
|
||||
import { useState } from "react";
|
||||
import "./App.css";
|
||||
import { decodeAttestationObject } from "./utils/decodeAttestationObject";
|
||||
import { parseAuthenticatorData } from "./utils/parseAuthenticatorData";
|
||||
import { getDomainFromOrigin } from "./utils/string";
|
||||
|
||||
type CredentialResponse = any;
|
||||
|
||||
@ -28,21 +26,25 @@ const RELAY_API_URL =
|
||||
process.env.REACT_APP_RELAY_API_URL || "http://localhost:3001";
|
||||
|
||||
function App() {
|
||||
const [pkpEthAddress, setPkpEthAddress] = useState<string>("");
|
||||
const [registeredPkpEthAddress, setRegisteredPkpEthAddress] = useState<
|
||||
string
|
||||
>("");
|
||||
const [
|
||||
googleCredentialResponse,
|
||||
setGoogleCredentialResponse,
|
||||
] = useState<CredentialResponse | null>(null);
|
||||
const [pkpPublicKey, setPkpPublicKey] = useState<string>("");
|
||||
const [registeredPkpPublicKey, setRegisteredPkpPublicKey] = useState<
|
||||
string
|
||||
>("");
|
||||
const [authenticatedPkpPublicKey, setAuthenticatedPkpPublicKey] = useState<
|
||||
string
|
||||
>("");
|
||||
const [status, setStatus] = useState("");
|
||||
const [selectedAuthMethod, setSelectedAuthMethod] = useState(6);
|
||||
const [
|
||||
webAuthnCredentialPublicKey,
|
||||
setWebAuthnCredentialPublicKey,
|
||||
] = useState<string>("");
|
||||
const [webAuthnSignature, setWebAuthnSignature] = useState<string>("");
|
||||
const [webAuthnSignatureBase, setWebAuthnSignatureBase] = useState<string>(
|
||||
""
|
||||
const [webAuthnUsername, setWebAuthnUsername] = useState<string>("");
|
||||
const [authSig, setAuthSig] = useState<JsonAuthSig | null>(null);
|
||||
const [executeJsSignature, setExecuteJsSignature] = useState<string | null>(
|
||||
null
|
||||
);
|
||||
|
||||
const handleLoggedInToGoogle = async (
|
||||
@ -61,8 +63,8 @@ function App() {
|
||||
requestId,
|
||||
setStatus,
|
||||
({ pkpEthAddress, pkpPublicKey }) => {
|
||||
setPkpEthAddress(pkpEthAddress);
|
||||
setPkpPublicKey(pkpPublicKey);
|
||||
setRegisteredPkpEthAddress(pkpEthAddress);
|
||||
setRegisteredPkpPublicKey(pkpPublicKey);
|
||||
}
|
||||
);
|
||||
};
|
||||
@ -97,7 +99,7 @@ function App() {
|
||||
{selectedAuthMethod === 6 && (
|
||||
<>
|
||||
<h3>
|
||||
Step 1: log in with Google. Upon OAuth success, we will
|
||||
Step 1: Log in with Google. Upon OAuth success, we will
|
||||
mint a PKP on your behalf.
|
||||
</h3>
|
||||
<GoogleLogin
|
||||
@ -107,8 +109,11 @@ function App() {
|
||||
}}
|
||||
useOneTap
|
||||
/>
|
||||
{pkpEthAddress && (
|
||||
<div>PKP Eth Address: {pkpEthAddress}</div>
|
||||
{registeredPkpEthAddress && (
|
||||
<div>
|
||||
Registered PKP Eth Address:{" "}
|
||||
{registeredPkpEthAddress}
|
||||
</div>
|
||||
)}
|
||||
<h3>
|
||||
<s>
|
||||
@ -128,8 +133,8 @@ function App() {
|
||||
signatureBase: "dummy",
|
||||
credentialPublicKey: "dummy",
|
||||
},
|
||||
pkpEthAddress,
|
||||
pkpPublicKey
|
||||
registeredPkpEthAddress,
|
||||
registeredPkpPublicKey
|
||||
)
|
||||
}
|
||||
>
|
||||
@ -139,93 +144,88 @@ function App() {
|
||||
)}
|
||||
{selectedAuthMethod === 3 && (
|
||||
<>
|
||||
<h3>Step 1: Register using WebAuthn.</h3>
|
||||
<h3>Step 1: Register to mint PKP. (optional username)</h3>
|
||||
<TextField
|
||||
label="Username"
|
||||
variant="outlined"
|
||||
onChange={e => setWebAuthnUsername(e.target.value)}
|
||||
/>
|
||||
<Button
|
||||
variant="contained"
|
||||
onClick={async () => {
|
||||
await handleWebAuthnRegister(
|
||||
webAuthnUsername,
|
||||
setStatus,
|
||||
({ attResp }) => {
|
||||
const attestationObject = base64url.toBuffer(
|
||||
attResp.response.attestationObject
|
||||
);
|
||||
|
||||
const {
|
||||
authData,
|
||||
} = decodeAttestationObject(
|
||||
window.cbor,
|
||||
attestationObject
|
||||
);
|
||||
|
||||
const parsedAuthData = parseAuthenticatorData(
|
||||
window.cbor,
|
||||
authData
|
||||
);
|
||||
|
||||
console.log(
|
||||
"storing credential public key in browser",
|
||||
{
|
||||
credentialPublicKey:
|
||||
parsedAuthData.credentialPublicKey,
|
||||
}
|
||||
);
|
||||
|
||||
// set in local state
|
||||
setWebAuthnCredentialPublicKey(
|
||||
hexlify(
|
||||
parsedAuthData.credentialPublicKey!
|
||||
)
|
||||
);
|
||||
({ pkpEthAddress, pkpPublicKey }) => {
|
||||
setRegisteredPkpEthAddress(pkpEthAddress);
|
||||
setRegisteredPkpPublicKey(pkpPublicKey);
|
||||
}
|
||||
);
|
||||
}}
|
||||
>
|
||||
Register
|
||||
</Button>
|
||||
<h3>Step 2: Authenticate using WebAuthn to mint PKP.</h3>
|
||||
{registeredPkpEthAddress && (
|
||||
<div>
|
||||
<b>Registered PKP Eth Address: </b>
|
||||
{registeredPkpEthAddress}
|
||||
</div>
|
||||
)}
|
||||
<h3>
|
||||
Step 2: Authenticate against Lit Nodes to generate auth
|
||||
sigs.
|
||||
</h3>
|
||||
<Button
|
||||
variant="contained"
|
||||
onClick={async () => {
|
||||
await handleWebAuthnAuthenticate(
|
||||
setStatus,
|
||||
webAuthnCredentialPublicKey,
|
||||
({ pkpEthAddress, pkpPublicKey }) => {
|
||||
setPkpEthAddress(pkpEthAddress);
|
||||
setPkpPublicKey(pkpPublicKey);
|
||||
},
|
||||
setWebAuthnSignature,
|
||||
setWebAuthnSignatureBase
|
||||
);
|
||||
const {
|
||||
authSig,
|
||||
pkpPublicKey,
|
||||
} = await handleWebAuthnAuthenticate(setStatus);
|
||||
setAuthSig(authSig);
|
||||
|
||||
// After authenticating, we can store the pkpPublicKey for executing a
|
||||
// Lit Action later.
|
||||
setAuthenticatedPkpPublicKey(pkpPublicKey);
|
||||
}}
|
||||
>
|
||||
Authenticate
|
||||
</Button>
|
||||
{authenticatedPkpPublicKey && authSig && (
|
||||
<>
|
||||
<div>
|
||||
<b>Authenticated PKP Public Key: </b>
|
||||
{authenticatedPkpPublicKey}
|
||||
</div>
|
||||
<div>
|
||||
<b>Auth Sig: </b>
|
||||
{JSON.stringify(authSig)}
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
<h3>
|
||||
<s>
|
||||
Step 3: Use Lit Network to obtain a session sig and
|
||||
then store an encryption condition.
|
||||
</s>
|
||||
(Session Sigs do not work currently.)
|
||||
Step 3: Generate session signatures and use them to
|
||||
execute a Lit Action.
|
||||
</h3>
|
||||
<Button
|
||||
variant="contained"
|
||||
onClick={() =>
|
||||
handleStoreEncryptionCondition(
|
||||
onClick={async () => {
|
||||
const signature = await handleExecuteJs(
|
||||
setStatus,
|
||||
selectedAuthMethod,
|
||||
googleCredentialResponse,
|
||||
{
|
||||
signature: webAuthnSignature,
|
||||
signatureBase: webAuthnSignatureBase,
|
||||
credentialPublicKey: webAuthnCredentialPublicKey,
|
||||
},
|
||||
pkpEthAddress,
|
||||
pkpPublicKey
|
||||
)
|
||||
}
|
||||
authSig!,
|
||||
authenticatedPkpPublicKey
|
||||
);
|
||||
setExecuteJsSignature(signature);
|
||||
}}
|
||||
>
|
||||
Encrypt With Lit
|
||||
Execute Lit Action
|
||||
</Button>
|
||||
{executeJsSignature && (
|
||||
<div>
|
||||
<b>Executed Lit Action Signature: </b>
|
||||
{executeJsSignature}
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
@ -234,6 +234,44 @@ function App() {
|
||||
|
||||
export default App;
|
||||
|
||||
async function handleExecuteJs(
|
||||
setStatusFn: (status: string) => void,
|
||||
authSig: JsonAuthSig,
|
||||
pkpPublicKey: string
|
||||
): Promise<string> {
|
||||
setStatusFn("Executing JS...");
|
||||
const litActionCode = `
|
||||
const go = async () => {
|
||||
// this requests a signature share from the Lit Node
|
||||
// the signature share will be automatically returned in the response from the node
|
||||
// and combined into a full signature by the LitJsSdk for you to use on the client
|
||||
// all the params (toSign, publicKey, sigName) are passed in from the LitJsSdk.executeJs() function
|
||||
const sigShare = await LitActions.signEcdsa({ toSign, publicKey, sigName });
|
||||
};
|
||||
|
||||
go();
|
||||
`;
|
||||
const litNodeClient = new LitJsSdk.LitNodeClient({
|
||||
litNetwork: "serrano",
|
||||
});
|
||||
await litNodeClient.connect();
|
||||
|
||||
const results = await litNodeClient.executeJs({
|
||||
code: litActionCode,
|
||||
authSig,
|
||||
// all jsParams can be used anywhere in your litActionCode
|
||||
jsParams: {
|
||||
// this is the string "Hello World" for testing
|
||||
toSign: [72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100],
|
||||
publicKey: `0x${pkpPublicKey}`,
|
||||
sigName: "sig1",
|
||||
},
|
||||
});
|
||||
console.log("results: ", results);
|
||||
|
||||
return results.signatures["sig1"].signature;
|
||||
}
|
||||
|
||||
async function mintPkpUsingRelayerGoogleAuthVerificationEndpoint(
|
||||
credentialResponse: any,
|
||||
setStatusFn: (status: string) => void
|
||||
@ -244,6 +282,7 @@ async function mintPkpUsingRelayerGoogleAuthVerificationEndpoint(
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
"api-key": "1234567890",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
idToken: credentialResponse.credential,
|
||||
@ -262,38 +301,6 @@ async function mintPkpUsingRelayerGoogleAuthVerificationEndpoint(
|
||||
}
|
||||
}
|
||||
|
||||
async function mintPkpUsingRelayerWebAuthnVerificationEndpoint(
|
||||
signature: string,
|
||||
signatureBase: string,
|
||||
credentialPublicKey: string,
|
||||
setStatusFn: (status: string) => void
|
||||
) {
|
||||
setStatusFn("Minting PKP with relayer...");
|
||||
|
||||
const mintRes = await fetch(`${RELAY_API_URL}/auth/webauthn`, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
signature,
|
||||
signatureBase,
|
||||
credentialPublicKey,
|
||||
}),
|
||||
});
|
||||
|
||||
if (mintRes.status < 200 || mintRes.status >= 400) {
|
||||
console.warn("Something wrong with the API call", await mintRes.json());
|
||||
setStatusFn("Uh oh, something's not quite right.");
|
||||
return null;
|
||||
} else {
|
||||
const resBody = await mintRes.json();
|
||||
console.log("Response OK", { body: resBody });
|
||||
setStatusFn("Successfully initiated minting PKP with relayer.");
|
||||
return resBody.requestId;
|
||||
}
|
||||
}
|
||||
|
||||
async function pollRequestUntilTerminalState(
|
||||
requestId: string,
|
||||
setStatusFn: (status: string) => void,
|
||||
@ -313,7 +320,12 @@ async function pollRequestUntilTerminalState(
|
||||
for (let i = 0; i < maxPollCount; i++) {
|
||||
setStatusFn(`Waiting for auth completion (poll #${i + 1})`);
|
||||
const getAuthStatusRes = await fetch(
|
||||
`${RELAY_API_URL}/auth/status/${requestId}`
|
||||
`${RELAY_API_URL}/auth/status/${requestId}`,
|
||||
{
|
||||
headers: {
|
||||
"api-key": "1234567890",
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
if (getAuthStatusRes.status < 200 || getAuthStatusRes.status >= 400) {
|
||||
@ -482,6 +494,7 @@ async function handleStoreEncryptionCondition(
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
"api-key": "1234567890",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
key: hashedEncryptedSymmetricKeyStr,
|
||||
@ -611,10 +624,24 @@ async function hashBytes({ bytes }: { bytes: Uint8Array }): Promise<string> {
|
||||
// }
|
||||
|
||||
async function handleWebAuthnRegister(
|
||||
username: string,
|
||||
setStatusFn: (status: string) => void,
|
||||
onSuccess: ({ attResp }: { attResp: any }) => void
|
||||
onSuccess: ({
|
||||
pkpEthAddress,
|
||||
pkpPublicKey,
|
||||
}: {
|
||||
pkpEthAddress: string;
|
||||
pkpPublicKey: string;
|
||||
}) => void
|
||||
) {
|
||||
const resp = await fetch(`${RELAY_API_URL}/generate-registration-options`);
|
||||
let url = `${RELAY_API_URL}/auth/webauthn/generate-registration-options`;
|
||||
|
||||
// Handle optional username
|
||||
if (username !== "") {
|
||||
url += `?username=${encodeURIComponent(username)}`;
|
||||
}
|
||||
|
||||
const resp = await fetch(url, { headers: { "api-key": "1234567890" } });
|
||||
|
||||
let attResp;
|
||||
try {
|
||||
@ -635,110 +662,110 @@ async function handleWebAuthnRegister(
|
||||
|
||||
console.log("attResp", { attResp });
|
||||
|
||||
const verificationResp = await fetch(
|
||||
`${RELAY_API_URL}/verify-registration`,
|
||||
// Verify and mint PKP.
|
||||
setStatusFn("Verifying WebAuthn registration...");
|
||||
const verificationAndMintResp = await fetch(
|
||||
`${RELAY_API_URL}/auth/webauthn/verify-registration`,
|
||||
{
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
"api-key": "1234567890",
|
||||
},
|
||||
body: JSON.stringify(attResp),
|
||||
body: JSON.stringify({ credential: attResp }),
|
||||
}
|
||||
);
|
||||
|
||||
const verificationJSON = await verificationResp.json();
|
||||
|
||||
if (verificationJSON && verificationJSON.verified) {
|
||||
setStatusFn("Successfully registered using WebAuthn!");
|
||||
onSuccess({ attResp });
|
||||
} else {
|
||||
setStatusFn(
|
||||
"Oh no, something went wrong during WebAuthn registration."
|
||||
if (
|
||||
verificationAndMintResp.status < 200 ||
|
||||
verificationAndMintResp.status >= 400
|
||||
) {
|
||||
console.warn(
|
||||
"Something went wrong with the API call",
|
||||
await verificationAndMintResp.json()
|
||||
);
|
||||
console.error("Error during WebAuthn registration", {
|
||||
err: JSON.stringify(verificationJSON),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
async function handleWebAuthnAuthenticate(
|
||||
setStatusFn: (status: string) => void,
|
||||
webAuthnCredentialPublicKey: string,
|
||||
onSuccess: (resp: any) => void,
|
||||
setWebAuthnSignatureFn: (signature: string) => void,
|
||||
setWebAuthnSignatureBaseFn: (signatureBase: string) => void
|
||||
) {
|
||||
const resp = await fetch(
|
||||
`${RELAY_API_URL}/generate-authentication-options`
|
||||
);
|
||||
|
||||
let asseResp;
|
||||
try {
|
||||
const opts = await resp.json();
|
||||
|
||||
asseResp = await startAuthentication(opts);
|
||||
} catch (error) {
|
||||
// TODO: handle error
|
||||
throw error;
|
||||
setStatusFn("Uh oh, something's not quite right.");
|
||||
return null;
|
||||
}
|
||||
|
||||
const verificationResp = await fetch(
|
||||
`${RELAY_API_URL}/verify-authentication`,
|
||||
{
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify(asseResp),
|
||||
}
|
||||
);
|
||||
|
||||
const verificationJSON = await verificationResp.json();
|
||||
|
||||
if (verificationJSON && verificationJSON.verified) {
|
||||
setStatusFn("Successfully authenticated using WebAuthn!");
|
||||
} else {
|
||||
setStatusFn(
|
||||
"Oh no, something went wrong during WebAuthn authentication."
|
||||
);
|
||||
console.error("Error during WebAuthn authentication", {
|
||||
err: JSON.stringify(verificationJSON),
|
||||
});
|
||||
}
|
||||
|
||||
const clientDataHash = await crypto.subtle.digest(
|
||||
"SHA-256",
|
||||
base64url.toBuffer(asseResp.response.clientDataJSON)
|
||||
);
|
||||
|
||||
const authDataBuffer = base64url.toBuffer(
|
||||
asseResp.response.authenticatorData
|
||||
);
|
||||
|
||||
const signatureBase = Buffer.concat([
|
||||
authDataBuffer,
|
||||
Buffer.from(clientDataHash),
|
||||
]);
|
||||
|
||||
const signature = base64url.toBuffer(asseResp.response.signature);
|
||||
|
||||
// mint PKP using Relayer
|
||||
console.log("Minting PKP using Relayer...", {
|
||||
signature: hexlify(signature),
|
||||
signatureBase: hexlify(signatureBase),
|
||||
webAuthnCredentialPublicKey,
|
||||
});
|
||||
const requestId = await mintPkpUsingRelayerWebAuthnVerificationEndpoint(
|
||||
hexlify(signature),
|
||||
hexlify(signatureBase),
|
||||
webAuthnCredentialPublicKey,
|
||||
setStatusFn
|
||||
const resBody = await verificationAndMintResp.json();
|
||||
console.log("Response OK", { body: resBody });
|
||||
setStatusFn(
|
||||
"Successfully registered using WebAuthn! PKP minting initiated..."
|
||||
);
|
||||
|
||||
// Poll until success
|
||||
await pollRequestUntilTerminalState(requestId, setStatusFn, onSuccess);
|
||||
|
||||
// Update state
|
||||
setWebAuthnSignatureFn(hexlify(signature));
|
||||
setWebAuthnSignatureBaseFn(hexlify(signatureBase));
|
||||
const mintRequestId = resBody.requestId;
|
||||
await pollRequestUntilTerminalState(mintRequestId, setStatusFn, onSuccess);
|
||||
}
|
||||
|
||||
const rpcUrl = process.env.REACT_APP_RPC_URL || "http://localhost:8545";
|
||||
|
||||
async function handleWebAuthnAuthenticate(
|
||||
setStatusFn: (status: string) => void
|
||||
): Promise<{
|
||||
authSig: JsonAuthSig;
|
||||
pkpPublicKey: string;
|
||||
}> {
|
||||
// Fetch latest blockHash
|
||||
setStatusFn("Fetching latest block hash...");
|
||||
const provider = new ethers.providers.JsonRpcProvider(rpcUrl);
|
||||
|
||||
const block = await provider.getBlock("latest");
|
||||
const blockHash = block.hash;
|
||||
|
||||
// Turn into byte array.
|
||||
const blockHashBytes = ethers.utils.arrayify(blockHash);
|
||||
console.log(
|
||||
"blockHash",
|
||||
blockHash,
|
||||
blockHashBytes,
|
||||
base64url(Buffer.from(blockHashBytes))
|
||||
);
|
||||
|
||||
// Construct authentication options.
|
||||
const rpId = getDomainFromOrigin(window.location.origin);
|
||||
console.log("Using rpId: ", { rpId });
|
||||
const authenticationOptions = {
|
||||
challenge: base64url(Buffer.from(blockHashBytes)),
|
||||
timeout: 60000,
|
||||
userVerification: "required",
|
||||
rpId,
|
||||
};
|
||||
|
||||
// Authenticate with WebAuthn.
|
||||
setStatusFn("Authenticating with WebAuthn...");
|
||||
const authenticationResponse = await startAuthentication(
|
||||
authenticationOptions
|
||||
);
|
||||
|
||||
// BUG: We need to make sure userHandle is base64url encoded.
|
||||
// Deep copy the authentication response.
|
||||
const actualAuthenticationResponse = JSON.parse(
|
||||
JSON.stringify(authenticationResponse)
|
||||
);
|
||||
actualAuthenticationResponse.response.userHandle = base64url.encode(
|
||||
authenticationResponse.response.userHandle
|
||||
);
|
||||
|
||||
// Call all nodes POST /web/auth/webauthn to generate authSig.
|
||||
setStatusFn("Verifying WebAuthn authentication against Lit Network...");
|
||||
const litNodeClient = new LitJsSdk.LitNodeClient({
|
||||
litNetwork: "serrano",
|
||||
});
|
||||
await litNodeClient.connect();
|
||||
|
||||
// Generate authMethod.
|
||||
const authMethod = litNodeClient.generateAuthMethodForWebAuthn(
|
||||
actualAuthenticationResponse
|
||||
);
|
||||
|
||||
// Get authSig.
|
||||
const { authSig, pkpPublicKey } = await litNodeClient.signSessionKey({
|
||||
authMethods: [authMethod],
|
||||
expiration: new Date(Date.now() + 24 * 60 * 60 * 1000).toISOString(),
|
||||
resources: [],
|
||||
});
|
||||
|
||||
return { authSig, pkpPublicKey };
|
||||
}
|
||||
|
6
src/utils/string.ts
Normal file
6
src/utils/string.ts
Normal file
@ -0,0 +1,6 @@
|
||||
export function getDomainFromOrigin(origin: string): string {
|
||||
// remove protocol with regex
|
||||
let newOrigin = origin.replace(/(^\w+:|^)\/\//, "");
|
||||
// remove port with regex
|
||||
return newOrigin.replace(/:\d+$/, "");
|
||||
}
|
Loading…
Reference in New Issue
Block a user