> ## Documentation Index
> Fetch the complete documentation index at: https://docs.dfns.co/llms.txt
> Use this file to discover all available pages before exploring further.

# Delegated 2/2: customer login and delegated wallets

> Give your users ownership and power to use their wallets directly.

For this example we will use Dfns [TypeScript SDK](/sdks/backend/typescript) to register end users (your customers) to the Dfns API and let them own their wallets and use it directly.

In this scenario, the wallets live in your organization but belong to your end users. Only they can do transactions and use the private key to sign messages. All actions require to be signed by their passkey. The SDK greatly simplifies that process.

<Steps>
  <Step title="Clone the example">
    This example contains all the functions you need to get started with login and wallets delegation.

    <CodeBlock lang="sh">
      git clone [https://github.com/dfns/dfns-sdk-ts.git](https://github.com/dfns/dfns-sdk-ts.git) --no-checkout
      cd dfns-sdk-ts
      git sparse-checkout set examples/sdk/nextjs-delegated
      git checkout m
      cd examples/sdk/nextjs-delegated/
    </CodeBlock>

    Edit `next.config.ts` to remove the line:

    ```typescript line to remove from next.config.ts: theme={null}
      transpilePackages: ['@dfns/sdk-browser'], // [!code --]
    ```

    Update the hardcoded dependencies and install the project:

    <CodeBlock lang="sh">
      npm i && npm remove @dfns/sdk @dfns/sdk-browser @dfns/sdk-keysigner && npm i @dfns/sdk @dfns/sdk-browser @dfns/sdk-keysigner
    </CodeBlock>
  </Step>

  <Step title="Prepare the environment">
    <Info>
      You can follow the README instructions.  For convenience the steps are gathered here.
    </Info>

    Copy `.env.example` to a new file `.env.local` and set the following values,

    * `DFNS_API_URL`: `https://api.dfns.io`
    * `DFNS_ORG_ID`: your Organization ID (found in the Dashboard: click your email then "Profile")
    * `DFNS_CRED_ID`: the `Signing Key Cred ID` created when you registered the service account. On the dashboard head to Settings > Service Accounts to copy it.
    * `DFNS_PRIVATE_KEY`: the private key from the step 'generate a keypair', the newlines should not be a problem
    * `DFNS_AUTH_TOKEN`: the `authToken` from above, the value should start with `eyJ0...`
    * `NEXT_PUBLIC_PASSKEYS_RELYING_PARTY_ID`: the passkey relying party id, aka, the domain where your app lives (Read more [here](https://developer.mozilla.org/en-US/docs/Web/API/PublicKeyCredentialCreationOptions#rp)).  During development on localhost, you can set it to `localhost`.
    * `NEXT_PUBLIC_PASSKEYS_RELYING_PARTY_NAME`: A string representing the name of the relying party, aka, your company name (e.g. "Acme"). The user will be presented with that name when creating or using a passkey.
      Run the development server

    <CodeBlock lang="sh">
      npm run dev
    </CodeBlock>

    And finally open `http://localhost:3000` in your browser.\`
  </Step>

  <Step title="Service account action signing">
    As any user on Dfns, your service account needs to sign its actions. The file `app/api/clients.ts` uses the Dfns SDK to register the service account private key into a signer, as well as a API client that will take care of gathering the right information and requesting signing when necessary.

    <CodeBlock title="[Backend] app/api/clients.ts" lang="typescript">
      {`export const apiClient = (authToken?: string) => {
            const signer = new AsymmetricKeySigner({
              credId: process.env.DFNS_CRED_ID!,
              privateKey: process.env.DFNS_PRIVATE_KEY!.replace(/\\\\n/g, '\\n'),
            })

            return new DfnsApiClient({
              orgId: process.env.DFNS_ORG_ID!,
              authToken: authToken ?? process.env.DFNS_AUTH_TOKEN!,
              baseUrl: process.env.DFNS_API_URL!,
              signer,
            })
            }`}
    </CodeBlock>
  </Step>

  <Step title="Delegated registration">
    The service account can use [delegated registration](/api-reference/auth/registration-flows#delegated-users-registration-flow) to register an end user (a.k.a. one of your customers) to Dfns.  Registering this user to your platform and validating his login is out of scope here, we just consider that you have properly authenticated your user before creating his Dfns account.  The flow is similar to users registration:

    1. Requesting a challenge from Dfns.  Note that the username comes from the frontend in this example, but it doesn't have to, you could be providing it directly from your backend.

    <CodeBlock title="[Backend] app/api/register/init/route.ts" lang="typescript">
      {`const client = apiClient()
            const challenge = await client.auth.createDelegatedRegistrationChallenge({
            body: { kind: 'EndUser', email: username },
            })`}
    </CodeBlock>

    2. Asking the customer to create a new credentials and sign the challenge with it.  This is done via the web front end:

    <CodeBlock title="[Frontend] app/register/page.tsx" lang="typescript">
      {`import { WebAuthnSigner } from '@dfns/sdk-browser'
            [...]
            const attestation = await webauthn.create(challenge)`}
    </CodeBlock>

    3. Registering the end user credentials
       Note that you can create a delegated wallet during registration.

    <CodeBlock title="[Backend] app/api/register/complete/route.ts" lang="typescript">
      {`const client = apiClient(temporaryAuthenticationToken)
            const registration = await client.auth.registerEndUser({
            body: {
              ...signedChallenge,
              wallets: [{ network: 'EthereumSepolia' }],
            },
            })`}
    </CodeBlock>
  </Step>

  <Step title="Delegated login">
    In a similar flow, once you have authenticated your user on your platform, you can log him into Dfns in order to let him use his wallet.

    <CodeBlock title="[Backend] app/api/login/route.ts" lang="typescript">
      {`const client = apiClient()
            const login = await client.auth.delegatedLogin({ body: { username } })`}
    </CodeBlock>

    You will get a token back from this call, that you can later use in all for all delegated actions.

    <Info>
      The user token will allow the user to call the Dfns API directly.  That's particularly important if you need to control your users actions.
    </Info>
  </Step>

  <Step title="Delegated calls to the API">
    The SDK provides an easy way to call the API with your delegated end user credentials:

    <CodeBlock title="[Backend] app/api/clients.ts" lang="typescript">
      {`export const delegatedClient = (authToken: string) => {
            return new DfnsDelegatedApiClient({
              orgId: process.env.DFNS_ORG_ID!,
              authToken,
              baseUrl: process.env.DFNS_API_URL!,
            })
            }`}
    </CodeBlock>

    The API requires the end user to sign any modifying action with his passkey.  For instance when requesting Dfns to issue a signature using his wallet:

    1. Request a challenge from Dfns.  Note that the username comes from the frontend in this example, but it doesn't have to, you could be providing it directly from your backend.

    <CodeBlock title="[Backend] app/api/wallets/signatures/init/route.ts" lang="typescript">
      {`const client = delegatedClient(authToken) // end user token here
            [...]
            const challenge = await client.wallets.generateSignatureInit({ walletId, body })`}
    </CodeBlock>

    2. Asking the customer to create a new credentials and sign the challenge with it.  This is done via the web front end:

    <CodeBlock title="[Frontend] app/wallets/page.tsx" lang="typescript">
      {`import { WebAuthnSigner } from '@dfns/sdk-browser'
            [...]
            const attestation = await webauthn.sign(challenge)`}
    </CodeBlock>

    3. Finally calling the signature API to trigger the action.

    <CodeBlock title="[Backend] app/api/register/complete/route.ts" lang="typescript">
      {`const client = delegatedClient(authToken)
            [...]
            const signature = await client.wallets.generateSignatureComplete(
              {
                walletId,
                body: requestBody,
              },
              signedChallenge
            )`}
    </CodeBlock>
  </Step>

  <Step title="Going further">
    Head to the SDK docs to better understand:

    * The [backend client](https://dfns.github.io/dfns-sdk-ts/#md:dfnsapiclient), used with your service account token, with the action [key signer](https://dfns.github.io/dfns-sdk-ts/#md:asymmetrickeysigner) for your service account to sign its actions automatically
    * The [backend "delegated" client](https://dfns.github.io/dfns-sdk-ts/#md:dfnsdelegatedapiclient), used with your delegated end user token
    * The [frontend browser sdk](https://dfns.github.io/dfns-sdk-ts/#md:browser-signers), to simplify the signing process with WebAuthn

    For a deeper understanding of delegated wallets and production implementation:

    * [Delegated wallets](/advanced/delegated-wallets) — architecture, trade-offs, and recovery strategies
    * [Implementing delegated wallets](/guides/developers/delegated-wallets) — full implementation guide with TypeScript and Python examples
    * [End-user recovery](/guides/developers/end-user-recovery) — implementing recovery flows

    More information about the other SDKs: [dfns-sdks](/sdks/)
  </Step>
</Steps>

<Check>
  Congratulations!  you now have all the tools to integrate Dfns into your own application.
</Check>

This is the end the Getting Started wizard. It's now time to explore the rest of our documentation and build your product!  [<Icon icon="arrow-right" /> Explore the documentation](/)
