# Minds Connect SDK

> Connect your application to Hello Minds. Your users sign in with their Minds account, and your app can see, message, and work with their Minds.

Connect your application to Hello Minds. Your users sign in with their Minds account, or create one on the spot, and your app can see, message, and work with their Minds.

The **Minds Connect SDK** is the TypeScript package that makes that connection. Add `@animocabrands/minds-connect` to your web app. Your users sign in on Hello Minds, including someone creating an account for the first time. Login and consent stay there. When they come back, `oauth.client` is the [Minds Client Library](/docs/get-started/client-library), ready to list their Minds, send messages, and do the rest of what they allowed. Connect keeps that session fresh before each call.

Your screens stay yours. Connect handles the redirect, the saved session, and sign-out from your app.

Register an OAuth client in the Builder console, copy the client ID into the SDK, and add a callback route at the redirect URI you registered. The examples below are TypeScript.

## Install

Types ship with the package. It runs in the browser. Load it from Vite, webpack, or another bundler. On the Next.js App Router, put the React bindings in a `"use client"` boundary.

```bash
npm install @animocabrands/minds-connect
```

| Import                               | Use when                                                             |
| ------------------------------------ | -------------------------------------------------------------------- |
| `@animocabrands/minds-connect`       | TypeScript without React                                             |
| `@animocabrands/minds-connect/react` | React. Needs `react` and `react-dom` 18 or newer as an optional peer |

## Register an OAuth client

Create a client on the [OAuth Client](/console?tab=oauth-client) tab. Copy the client ID into `clientId`. The ID is public. There is no client secret to store.

The redirect URI is the page in your app that finishes sign-in. The authorized origin is the site allowed to start it. Both have to match the values you register, including scheme, host, and port.

Keep the user in the same browser tab. Connect stores a one-time check in `sessionStorage` for that tab. A new tab, a popup, or a bookmarked callback URL cannot finish sign-in.

The tab lists **Available scopes**. That is this client's allowlist. You cannot edit it there. Pass scopes from that list with `MindsScope`. Sign-in fails if you ask for one that is not on it. `MindsScope.Email` is the signed-in user's account email, and it is on the allowlist. `MindsScope.MindsEmail` is a different scope: the address of one of their Minds.

## React

Wrap the router once with `MindsConnect`, so the home page and the callback share one client. Options are read when the provider mounts. Reload the page to change them.

Put `LoginCallback` on the same path as `redirectUri`. `signIn()` sends the user to Hello Minds. After they return, call the Builder API on `oauth.client`.

```tsx
import  from "react-router-dom";
import {
  LoginCallback,
  MindsConnect,
  MindsScope,
  useMindsConnect,
  type MindsOAuthOptions,
} from "@animocabrands/minds-connect/react";

const opts: MindsOAuthOptions = {
  clientId: "YOUR_CLIENT_ID",
  redirectUri: `$/callback`,
  scopes: [MindsScope.Email, MindsScope.MindsList],
};

export function Root() {
  return (

  );
}

function Home() {
  const  = useMindsConnect();

  if (!isInitialized || !oauth) return Loading…;
  if (!isAuthenticated) {
    return (

        Sign in with Minds

    );
  }

  async function listMinds() {
    const minds = await oauth.client.listMinds();
    console.log(minds);
  }

  return (
    <>

        List minds

        Log out

    </>
  );
}

function Callback() {
  const navigate = useNavigate();
  return (
     navigate("/", )}
      onError=
    />
  );
}
```

Leave `LoginCallback` without children to show its built-in status. If you pass children, they always render. Send the user home from `onSuccess`.

`useMindsConnect()` also gives you `hasScopes`, `tokens`, and `getAccessToken`.

## Without React

The steps are the same. Share one options module, start sign-in from a button, and finish it on the callback page. The callback is a new page load, so construct `MindsOAuth` again with the same `clientId` and `redirectUri`.

`onTokensChanged` runs in this tab when Connect writes the session: sign-out, a refresh, or a failed refresh that clears the store. It does not run on a fresh page load. Read `oauth.tokens` when you paint the first view.

```ts
// oauth.ts
import  from "@animocabrands/minds-connect";

export const opts: MindsOAuthOptions = {
  clientId: "YOUR_CLIENT_ID",
  redirectUri: `$/callback`,
  scopes: [MindsScope.Email, MindsScope.MindsList],
};

export const oauth = new MindsOAuth(opts);
```

```ts
// main.ts — home page
import  from "./oauth";

const connectBtn = document.getElementById("connect");
const listBtn = document.getElementById("list");
const logoutBtn = document.getElementById("logout");

oauth.onTokensChanged((tokens) => {
  const signedIn = Boolean(tokens);
  if (connectBtn) connectBtn.hidden = signedIn;
  if (listBtn) listBtn.hidden = !signedIn;
  if (logoutBtn) logoutBtn.hidden = !signedIn;
});

connectBtn?.addEventListener("click", async () => {
  await oauth.signIn();
});

listBtn?.addEventListener("click", async () => {
  const minds = await oauth.client.listMinds();
  console.log(minds);
});

logoutBtn?.addEventListener("click", async () => {
  await oauth.signOut();
});
```

```ts
// callback.ts — same path as redirectUri
import  from "@animocabrands/minds-connect";
import  from "./oauth";

try {
  await oauth.handleRedirect();
  window.location.replace("/");
} catch (err) {
  if (err instanceof OAuthRedirectError) {
    console.error(err.error, err.errorDescription);
  } else {
    console.error(err);
  }
}
```

`handleRedirect()` checks the returned state, exchanges the code, and stores the tokens. If the user denies access, or the state does not match, it throws `OAuthRedirectError`.

## Scopes

A scope is what the signed-in user allows your app to do. Put the full set on `opts.scopes` when you construct the SDK. `MindsScope` is the set of TypeScript constants for those ids. Both entry points export it.

To ask for more later, call `signIn()` with the **full** list you want, including scopes they already granted. `hasScopes` tells you whether that trip is needed.

```ts
import  from "@animocabrands/minds-connect";

const scopes = [MindsScope.MindsList, MindsScope.ConversationsList, MindsScope.MessagingSend];

if (oauth.tokens && !oauth.hasScopes(scopes)) {
  await oauth.signIn();
}
```

In React, use the same list with `isAuthenticated`, `hasScopes`, and `signIn`.

`oauth.client` can only call what that grant includes. `listMinds()` needs `MindsScope.MindsList`. Sending a message needs `MindsScope.MessagingSend`. The method list is on the [client library](/docs/get-started/client-library) page.

| `MindsScope`                         | Scope                       | What the user allows                      |
| ------------------------------------ | --------------------------- | ----------------------------------------- |
| `MindsScope.Email`                   | `email`                     | See their email                           |
| `MindsScope.MindsList`               | `minds:list`                | See their Minds                           |
| `MindsScope.MindsStatus`             | `minds:status`              | See whether their Minds are on            |
| `MindsScope.MindsCognition`          | `minds:cognition`           | See their Minds' cognition                |
| `MindsScope.MindsSkillsList`         | `minds:skills:list`         | See their Minds' skills                   |
| `MindsScope.MindsToolsList`          | `minds:tools:list`          | See their Minds' tools                    |
| `MindsScope.MindsAppsList`           | `minds:apps:list`           | See their Minds' apps                     |
| `MindsScope.MindsEmail`              | `minds:email`               | See their Minds' email                    |
| `MindsScope.MindsWallets`            | `minds:wallets`             | See their Minds' wallet addresses         |
| `MindsScope.MindsAwaken`             | `minds:awaken`              | Awaken Minds for them                     |
| `MindsScope.MindsEnable`             | `minds:enable`              | Turn their Minds on                       |
| `MindsScope.MindsDisable`            | `minds:disable`             | Turn their Minds off                      |
| `MindsScope.MindsSkillsEquip`        | `minds:skills:equip`        | Equip skills on their Minds               |
| `MindsScope.MindsSkillsUnequip`      | `minds:skills:unequip`      | Unequip skills on their Minds             |
| `MindsScope.MindsToolsEquip`         | `minds:tools:equip`         | Equip tools on their Minds                |
| `MindsScope.MindsToolsUnequip`       | `minds:tools:unequip`       | Unequip tools on their Minds              |
| `MindsScope.MindsAppsEquip`          | `minds:apps:equip`          | Equip apps on their Minds                 |
| `MindsScope.MindsAppsUnequip`        | `minds:apps:unequip`        | Unequip apps on their Minds               |
| `MindsScope.ConversationsCreate`     | `conversations:create`      | Start chats with their Minds              |
| `MindsScope.ConversationsList`       | `conversations:list`        | See their chats                           |
| `MindsScope.ConversationsRead`       | `conversations:read`        | See a chat with their Minds               |
| `MindsScope.MessagingSend`           | `messaging:send`            | Send messages as them                     |
| `MindsScope.MessagingBeacon`         | `messaging:beacon`          | Nudge their Minds                         |
| `MindsScope.MessagingHistory`        | `messaging:history`         | See their chat history                    |
| `MindsScope.MessagingActivityStream` | `messaging:activity:stream` | Watch activity for one of their Minds     |
| `MindsScope.MessagingStream`         | `messaging:stream`          | Watch messaging events across their Minds |

## Where the calls run

A web app with no backend can stay in Connect. `oauth.client` is the client library, already aimed at the signed-in user. Connect depends on `@animocabrands/minds-client-lib`, so you do not install that package yourself for browser calls.

```ts
const minds = await oauth.client.listMinds();
```

When you also have a backend, keep Connect in the browser for sign-in and refresh. Install the client library on the server, and pass it the access token the page sends you. Listing Minds, sending messages, and the longer work can then run there. The methods are the same. They are documented on the [client library](/docs/get-started/client-library) page.

```ts
import  from "@animocabrands/minds-client-lib";

const accessToken = req.headers.authorization?.replace(/^Bearer\s+/i, "");
const minds = await createMindsClient().listMinds();
```

`getAccessToken()` returns a token that is still valid, refreshing when it is within 60 seconds of expiry. It returns `null` when there is no session. `oauth.tokens` is the stored snapshot, and that snapshot can already be expired, so use `getAccessToken()` when you send the token to your backend.

## Sign out

`signOut()` clears the session in your app and revokes the refresh token. Their Hello Minds account stays signed in, so the next visit can continue without creating an account again.

```ts
await oauth.signOut();
```

## Session

The session is stored in `localStorage`, under `minds_oauth_session:` plus your client ID. It survives reload and other tabs on this origin. Any script on the page can read it.

Pass `storage` when you want a different store. Extend `TokenStore` and implement `get`, `set`, and `clear`. `signOut()` clears that store.

| Field          | Meaning                                                                |
| -------------- | ---------------------------------------------------------------------- |
| `accessToken`  | Bearer token for Builder API calls                                     |
| `refreshToken` | Replaced on each refresh. The store keeps the latest                   |
| `expiresIn`    | Seconds remaining when you read the store                              |
| `scope`        | Granted scopes, separated by spaces. Use `hasScopes` to check coverage |

## Options

The same object goes to `new MindsOAuth(opts)` and to `MindsConnect`.

| Option        | Required | Default          | What you pass                                                                                                                  |
| ------------- | -------- | ---------------- | ------------------------------------------------------------------------------------------------------------------------------ |
| `clientId`    | yes      | —                | Public client ID from the [OAuth Client](/console?tab=oauth-client) tab                                                        |
| `redirectUri` | yes      | —                | Callback URL you registered, including origin                                                                                  |
| `scopes`      | yes      | —                | Full `MindsScope` list for the first `signIn()`. Must not be empty. Include `MindsScope.Email` when you need the account email |
| `storage`     | no       | `"localStorage"` | `"localStorage"`, or your own `TokenStore`                                                                                     |

`signIn()` can also take `state` (a string or object you get back from `handleRedirect`) and `scopes` (a full list that replaces `opts.scopes` for that trip).

## Methods

| Area        | What you call                                                            |
| ----------- | ------------------------------------------------------------------------ |
| Sign-in     | `signIn`, `handleRedirect`                                               |
| Session     | `getAccessToken`, `tokens`, `hasScopes`, `onTokensChanged`, `signOut`    |
| Builder API | `client` — the client library (`listMinds`, `sendMessage`, and the rest) |
| React       | `MindsConnect`, `useMindsConnect`, `LoginCallback`                       |

`MindsOAuth`, `MindsScope`, `OAuthRedirectError`, `TokenStore`, and the types `MindsOAuthOptions`, `TokenSuccess`, `SignInOptions`, and `OAuthSession` are exported from `@animocabrands/minds-connect`. The React entry re-exports `MindsScope`.
