Guía de Integración Keyless
A un alto nivel, hay tres pasos a seguir para integrar Cuentas Keyless.
- Configurar tu integración OpenID con tu IdP. En este paso, la dApp se registrará con el IdP de elección (ej. Google) y recibirá un client_id
- Instalar el SDK de TypeScript de Aptos.
- Integrar soporte de Cuenta Keyless en tu cliente de aplicación
- Configurar el flujo "Iniciar Sesión con [Idp]"para tu usuario.
- Instanciar la KeylessAccountdel usuario
- Firmar y enviar transacciones a través de la KeylessAccount.
 
- Configurar el flujo 
Implementación de Ejemplo
Sección titulada «Implementación de Ejemplo»Puedes encontrar una aplicación de ejemplo demostrando integración básica de Keyless con Google en el repositorio aptos-keyless-example. Sigue las direcciones en el README para comenzar con el ejemplo. Para instrucciones más detalladas sobre keyless, por favor lee el resto de esta guía de integración.
- 
Paso 1. Configurar tu integración OpenID con tu IdP El primer paso es configurar la configuración con tu(s) IdP(s). 
- 
Paso 2. Instalar el SDK de TypeScript de Aptos Ventana de terminal # Keyless es soportado en la versión 1.18.1 y superiorpnpm install @aptos-labs/ts-sdk
- 
Paso 3. Pasos de Integración del Cliente Abajo están los pasos predeterminados para que un cliente integre Cuentas Keyless 1. Presentar al usuario un botón “Iniciar Sesión con [IdP]” en la UISección titulada «1. Presentar al usuario un botón “Iniciar Sesión con [IdP]” en la UI»- 
En el fondo, creamos un par de claves efímeras. Almacena esto en almacenamiento local. import {EphemeralKeyPair} from '@aptos-labs/ts-sdk';const ephemeralKeyPair = EphemeralKeyPair.generate();
- 
Guardar el EphemeralKeyPairen almacenamiento local, indexado por sunonce.// Esto guarda el EphemeralKeyPair en almacenamiento localstoreEphemeralKeyPair(ephemeralKeyPair);
 Implementación de ejemplo parastoreEphemeralKeyPair/*** Almacenar el par de claves efímeras en localStorage.*/export const storeEphemeralKeyPair = (ekp: EphemeralKeyPair): void =>localStorage.setItem("@aptos/ekp", encodeEphemeralKeyPair(ekp));/*** Recuperar el par de claves efímeras de localStorage si existe.*/export const getLocalEphemeralKeyPair = (): EphemeralKeyPair | undefined => {try {const encodedEkp = localStorage.getItem("@aptos/ekp");return encodedEkp ? decodeEphemeralKeyPair(encodedEkp) : undefined;} catch (error) {console.warn("Failed to decode ephemeral key pair from localStorage",error);return undefined;}};/*** Convertir a string los pares de claves efímeras para ser almacenados en localStorage*/export const encodeEphemeralKeyPair = (ekp: EphemeralKeyPair): string =>JSON.stringify(ekp, (_, e) => {if (typeof e === "bigint") return { __type: "bigint", value: e.toString() };if (e instanceof Uint8Array)return { __type: "Uint8Array", value: Array.from(e) };if (e instanceof EphemeralKeyPair)return { __type: "EphemeralKeyPair", data: e.bcsToBytes() };return e;});/*** Parsear los pares de claves efímeras de un string*/export const decodeEphemeralKeyPair = (encodedEkp: string): EphemeralKeyPair =>JSON.parse(encodedEkp, (_, e) => {if (e && e.__type === "bigint") return BigInt(e.value);if (e && e.__type === "Uint8Array") return new Uint8Array(e.value);if (e && e.__type === "EphemeralKeyPair")return EphemeralKeyPair.fromBytes(e.data);return e;});- 
Preparar los parámetros URL de la URL de inicio de sesión. Establecer el redirect_uriyclient_ida tus valores configurados con el IdP. Establecer elnonceal nonce delEphemeralKeyPairdel paso 1.1.const redirectUri = 'https://.../login/callback'const clientId = env.IDP_CLIENT_ID// Obtener el nonce asociado con ephemeralKeyPairconst nonce = ephemeralKeyPair.nonce
- 
Construir la URL de inicio de sesión para que el usuario se autentique con el IdP. Asegúrate de que el scope openidesté establecido. Otros scopes comoemailyprofilepueden establecerse basados en las necesidades de tu app.const loginUrl = `https://accounts.google.com/o/oauth2/v2/auth?response_type=id_token&scope=openid+email+profile&nonce=${nonce}&redirect_uri=${redirectUri}&client_id=${clientId}`
- 
Cuando el usuario haga clic en el botón de inicio de sesión, redirigir al usuario a la loginUrlque se creó en el paso 1.4.
 2. Manejar el callback parseando el token y crear una cuenta Keyless para el usuarioSección titulada «2. Manejar el callback parseando el token y crear una cuenta Keyless para el usuario»- 
Una vez que el usuario completa el flujo de inicio de sesión, será redirigido al redirect_uriestablecido en el paso 1. El JWT se establecerá en la URL como un parámetro de búsqueda en un fragmento URL, indexado porid_token. Extraer el JWT delwindowhaciendo lo siguiente:const parseJWTFromURL = (url: string): string | null => {const urlObject = new URL(url);const fragment = urlObject.hash.substring(1);const params = new URLSearchParams(fragment);return params.get('id_token');};// window.location.href = https://.../login/google/callback#id_token=...const jwt = parseJWTFromURL(window.location.href)
- 
Decodificar el JWT y extraer el valor nonce del payload. import { jwtDecode } from 'jwt-decode';const payload = jwtDecode<{ nonce: string }>(jwt);const jwtNonce = payload.nonce
- 
Obtener el EphemeralKeyPairalmacenado en el paso 1.2. Asegúrate de validar que el nonce coincida con el nonce decodificado y que elEphemeralKeyPairno haya expirado.const ekp = getLocalEphemeralKeyPair();// Validar el EphemeralKeyPairif (!ekp || ekp.nonce !== jwtNonce || ekp.isExpired() ) {throw new Error("Ephemeral key pair not found or expired");}
- 
Instanciar la KeylessAccountdel usuarioDependiendo del tipo de Keyless que estés usando, sigue las instrucciones abajo: - Keyless Normal
 import {Aptos, AptosConfig, Network} from '@aptos-labs/ts-sdk';const aptos = new Aptos(new AptosConfig({ network: Network.DEVNET })); // Configura tu red aquíconst keylessAccount = await aptos.deriveKeylessAccount({jwt,ephemeralKeyPair,});- Keyless Federado
 import {Aptos, AptosConfig, Network} from '@aptos-labs/ts-sdk';const aptos = new Aptos(new AptosConfig({ network: Network.DEVNET })); // Configura tu red aquíconst keylessAccount = await aptos.deriveKeylessAccount({jwt,ephemeralKeyPair,jwkAddress: jwkOwner.accountAddress});
 3. Almacenar la KeylessAccount en almacenamiento local (Opcional)Sección titulada «3. Almacenar la KeylessAccount en almacenamiento local (Opcional)»- 
Después de que la cuenta ha sido derivada, almacenar la KeylessAccounten almacenamiento local. Esto permite al usuario regresar a la aplicación sin tener que re-autenticarse.export const storeKeylessAccount = (account: KeylessAccount): void =>localStorage.setItem("@aptos/account", encodeKeylessAccount(account));export const encodeKeylessAccount = (account: KeylessAccount): string =>JSON.stringify(account, (_, e) => {if (typeof e === "bigint") return { __type: "bigint", value: e.toString() };if (e instanceof Uint8Array)return { __type: "Uint8Array", value: Array.from(e) };if (e instanceof KeylessAccount)return { __type: "KeylessAccount", data: e.bcsToBytes() };return e;});
- 
Cuando el usuario regrese a la aplicación, recuperar la KeylessAccountde almacenamiento local y usarla para firmar transacciones.export const getLocalKeylessAccount = (): KeylessAccount | undefined => {try {const encodedAccount = localStorage.getItem("@aptos/account");return encodedAccount ? decodeKeylessAccount(encodedAccount) : undefined;} catch (error) {console.warn("Failed to decode account from localStorage",error);return undefined;}};export const decodeKeylessAccount = (encodedAccount: string): KeylessAccount =>JSON.parse(encodedAccount, (_, e) => {if (e && e.__type === "bigint") return BigInt(e.value);if (e && e.__type === "Uint8Array") return new Uint8Array(e.value);if (e && e.__type === "KeylessAccount")return KeylessAccount.fromBytes(e.data);return e;});
 4. Enviar transacciones a la blockchain de AptosSección titulada «4. Enviar transacciones a la blockchain de Aptos»- 
Crear la transacción que quieres enviar. Abajo hay una transacción simple de transferencia de moneda por ejemplo: import {Account} from '@aptos-labs/ts-sdk';const bob = Account.generate();const transaction = await aptos.transferCoinTransaction({sender: keylessAccount.accountAddress,recipient: bob.accountAddress,amount: 100,});
- 
Firmar y enviar la transacción a la cadena. const committedTxn = await aptos.signAndSubmitTransaction({ signer: keylessAccount, transaction });
- 
Esperar a que la transacción sea procesada en cadena const committedTransactionResponse = await aptos.waitForTransaction({ transactionHash: committedTxn.hash });
 
-