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

# Wallet Hub Sign-In

> List your store in the Ebioro wallet and receive users already signed in

## Overview

The **Hub** in the Ebioro wallet app lists partner stores. When a user opens your store from the Hub, Ebioro can hand it a signed token identifying the user, so they arrive **already signed in** — no separate registration or login. The store opens inside the app in a webview.

This is a distribution channel for merchants: appear in the Hub, and every wallet user is a potential one-tap customer.

There are two ways to list a store:

<CardGroup cols={2}>
  <Card title="No authentication" icon="store" color="#0092DF">
    Register a single **webview URL** and Ebioro opens it directly from the Hub. Best for a public catalog with no user accounts.
  </Card>

  <Card title="Authenticated sign-in" icon="right-to-bracket" color="#04394F">
    Ebioro hands your **auth endpoint** a signed token, so the user lands in a session you created — **already signed in**. Best when users have accounts on your store.
  </Card>
</CardGroup>

<Info>
  Stores are listed by Ebioro, not self-service. To appear in the Hub — and to register your auth endpoint, icon, and any custom headers — contact us at [support@ebioro.com](mailto:support@ebioro.com).
</Info>

## How authenticated sign-in works

<Steps>
  <Step title="User opens your store" icon="hand-pointer">
    The user taps your store in the wallet Hub.
  </Step>

  <Step title="Ebioro signs a token" icon="signature">
    A short-lived **JWT** containing the user's name, last name, email, and phone.
  </Step>

  <Step title="Ebioro calls your endpoint" icon="paper-plane">
    A `POST` to your registered **auth endpoint** with `{ "token": "<jwt>" }`.
  </Step>

  <Step title="You verify the token" icon="shield-check">
    Check the signature and expiry before trusting any field.
  </Step>

  <Step title="You start a session" icon="user-check">
    Find or create the user (match on email or phone) and open a session.
  </Step>

  <Step title="You return a link" icon="link">
    Respond with `{ "url": "<authenticated link>" }`.
  </Step>

  <Step title="The user is signed in" icon="mobile-screen">
    Ebioro opens that URL in the in-app webview — the user lands already signed in.
  </Step>
</Steps>

## Your auth endpoint

Register an HTTPS endpoint that accepts the token and returns a session URL.

**Request** — Ebioro calls your endpoint:

```http theme={null}
POST /your/auth/endpoint
Content-Type: application/json

{ "token": "<JWT>" }
```

Any **custom headers** you agree on at listing time (for example a shared `x-api-key`) are sent with this request, so your endpoint can confirm the call really came from Ebioro.

**Response** — return the URL that opens an authenticated session:

```json theme={null}
{ "url": "https://your-store.com/session?token=abc123" }
```

Ebioro opens that `url` in the webview. Return HTTP `200` with a `url` field; anything else is treated as a failure.

## The token

|           |                 |
| --------- | --------------- |
| Algorithm | EdDSA (Ed25519) |
| Lifetime  | 2 hours         |

Payload:

```json theme={null}
{
  "name": "Carlos",
  "lastName": "García",
  "email": "carlos@example.com",
  "phone": "+5355555555",
  "iat": 1718131200,
  "exp": 1718138400
}
```

### Getting the public key

Ebioro signs with its Stellar signing key. The matching public key is published in the `SIGNING_KEY` field of the Stellar TOML:

| Environment | TOML URL                                                     |
| ----------- | ------------------------------------------------------------ |
| Sandbox     | `https://test-walletapi.ebioro.com/.well-known/stellar.toml` |
| Production  | `https://api.ebioro.com/.well-known/stellar.toml`            |

The key is in Stellar `G...` format. To verify a standard Ed25519 JWT, convert it to a public key object as shown below.

### Verifying the token (Node.js)

```javascript theme={null}
import { StrKey, StellarToml } from '@stellar/stellar-sdk';
import { jwtVerify } from 'jose';
import { createPublicKey } from 'crypto';

// Sandbox: test-walletapi.ebioro.com — Production: api.ebioro.com
const EBIORO_DOMAIN = process.env.EBIORO_DOMAIN || 'test-walletapi.ebioro.com';

// Your store's webview host as registered with Ebioro — the token's `aud` claim.
const STORE_HOST = 'www.example.store';

let cachedKey; // The signing key rarely changes — fetch the TOML once and reuse.

async function getSigningKey() {
  if (cachedKey) return cachedKey;
  const toml = await StellarToml.Resolver.resolve(EBIORO_DOMAIN);
  cachedKey = toml.SIGNING_KEY; // Stellar G... public key
  return cachedKey;
}

export async function verifyEbioroToken(token: string) {
  const stellarPublicKey = await getSigningKey();

  // Convert the Stellar G... key into an SPKI Ed25519 public key
  const rawPublicKey = StrKey.decodeEd25519PublicKey(stellarPublicKey);
  const spkiPrefix = Buffer.from('302a300506032b6570032100', 'hex');
  const spkiKey = Buffer.concat([spkiPrefix, rawPublicKey]);
  const publicKey = createPublicKey({ key: spkiKey, format: 'der', type: 'spki' });

  // Throws if the signature is invalid, the token has expired, or the audience
  // does not match. STORE_HOST is your store's webview host as registered with
  // Ebioro (e.g. 'www.example.store').
  const { payload } = await jwtVerify(token, publicKey, { audience: STORE_HOST });
  return payload; // { name, lastName, email, phone, aud, iat, exp }
}
```

The `jwtVerify` call checks the signature, the `exp` expiry, and the `aud` (audience). With the verified payload, look the user up by email or phone, create them if they don't exist, start a session, and return its URL.

### Verify the audience

Every token Ebioro mints is scoped to a single store: its `aud` claim is set to **your store's webview host** (the hostname of the webview URL you registered, e.g. `www.example.store`). Pass that value as the `audience` option to `jwtVerify`, as shown above.

Verifying `aud` ensures a token issued for another store cannot be replayed against your endpoint. It is optional but strongly recommended — without it, any valid Ebioro token would be accepted. If you're unsure of the exact host registered for your store, ask us when you onboard.

<Warning>
  The sample defaults to the **sandbox** key. Before going live, set `EBIORO_DOMAIN` to `api.ebioro.com` — verifying production tokens against the sandbox key will fail every sign-in.
</Warning>

<Warning>
  Always verify the signature before trusting any field in the token, and confirm the custom header(s) agreed with Ebioro. Never accept an unverified token to sign a user in.
</Warning>

## Stores without authentication

If your store has no user accounts, you can skip all of the above: register a single **webview URL** and Ebioro opens it directly from the Hub. No token, no endpoint. Contact us to set this up.
