Skip to content

Commit d5596cd

Browse files
docs: Update documentation for controller PR #2315 (#198)
Updates documentation to reflect changes made in: feat: add headless mode support to controller SDK Related controller PR: cartridge-gg/controller#2315 Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
1 parent 8b1521d commit d5596cd

File tree

4 files changed

+478
-4
lines changed

4 files changed

+478
-4
lines changed

src/pages/controller/examples/react.md

Lines changed: 98 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -258,7 +258,104 @@ export function MultiAuthConnectWallet() {
258258
}
259259
```
260260

261-
### 4. Performing Transactions
261+
### 4. Headless Authentication
262+
263+
For programmatic authentication without opening any UI, you can use headless mode in your React components:
264+
265+
```tsx
266+
import { useCallback, useState } from 'react'
267+
import { useConnect } from '@starknet-react/core'
268+
import { ControllerConnector } from '@cartridge/connector'
269+
270+
export function HeadlessLogin() {
271+
const { connectAsync, connectors } = useConnect()
272+
const [username, setUsername] = useState('')
273+
const [loading, setLoading] = useState(false)
274+
const controller = connectors[0] as ControllerConnector
275+
276+
const handleHeadlessLogin = useCallback(async (signer: string) => {
277+
if (!username) {
278+
alert('Please enter a username')
279+
return
280+
}
281+
282+
setLoading(true)
283+
try {
284+
// Ensure we start fresh
285+
if (controller.account) {
286+
await controller.disconnect()
287+
}
288+
289+
// Headless authentication
290+
const account = await controller.connect({
291+
username,
292+
signer,
293+
})
294+
295+
if (!account) {
296+
throw new Error('Failed to authenticate')
297+
}
298+
299+
// Sync with starknet-react state
300+
await connectAsync({ connector: controller })
301+
302+
alert(`Successfully authenticated as ${username}!`)
303+
} catch (error) {
304+
console.error('Headless authentication failed:', error)
305+
alert('Authentication failed: ' + (error as Error).message)
306+
} finally {
307+
setLoading(false)
308+
}
309+
}, [username, controller, connectAsync])
310+
311+
return (
312+
<div className="space-y-4">
313+
<div>
314+
<label htmlFor="username">Username:</label>
315+
<input
316+
id="username"
317+
type="text"
318+
value={username}
319+
onChange={(e) => setUsername(e.target.value)}
320+
placeholder="Enter your username"
321+
disabled={loading}
322+
/>
323+
</div>
324+
325+
<div className="grid gap-2">
326+
<button
327+
onClick={() => handleHeadlessLogin('webauthn')}
328+
disabled={loading || !username}
329+
>
330+
Login with Passkey
331+
</button>
332+
333+
<button
334+
onClick={() => handleHeadlessLogin('metamask')}
335+
disabled={loading || !username}
336+
>
337+
Login with MetaMask
338+
</button>
339+
340+
<button
341+
onClick={() => handleHeadlessLogin('google')}
342+
disabled={loading || !username}
343+
>
344+
Login with Google
345+
</button>
346+
</div>
347+
348+
{loading && <p>Authenticating...</p>}
349+
</div>
350+
)
351+
}
352+
```
353+
354+
:::warning
355+
Headless mode requires that the user already has the specified signer (passkey, OAuth account, EVM wallet) associated with their Cartridge username. For new user registration, use the regular `connect()` flow which opens the UI.
356+
:::
357+
358+
### 5. Performing Transactions
262359

263360
Execute transactions using the `account` object from `useAccount` hook:
264361

src/pages/controller/getting-started.mdx

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,41 @@ const account = await controller.connect();
3535
const phantomAccount = await controller.connect(["phantom-evm"]);
3636
```
3737

38+
### Headless Authentication
39+
40+
For programmatic authentication without opening any UI, you can use headless mode by providing a `username` and `signer`:
41+
42+
```ts
43+
import Controller from "@cartridge/controller";
44+
45+
const controller = new Controller({});
46+
47+
// Headless authentication with WebAuthn/Passkey
48+
const account = await controller.connect({
49+
username: "alice",
50+
signer: "webauthn",
51+
});
52+
53+
// Headless authentication with password
54+
const account = await controller.connect({
55+
username: "alice",
56+
signer: "password",
57+
password: "your-secure-password",
58+
});
59+
60+
// Headless authentication with OAuth providers
61+
await controller.connect({ username: "alice", signer: "google" });
62+
await controller.connect({ username: "alice", signer: "discord" });
63+
64+
// Headless authentication with EVM wallets
65+
await controller.connect({ username: "alice", signer: "metamask" });
66+
await controller.connect({ username: "alice", signer: "phantom-evm" });
67+
```
68+
69+
:::info
70+
Headless mode performs authentication in a hidden iframe without displaying any UI. However, if session policies need approval or verification, the UI will open automatically to request user consent.
71+
:::
72+
3873
When `connect()` is called, users will see an improved controller creation interface with username autocomplete functionality. As users type their username, they'll see matching existing accounts with user profiles, making it easier to connect to existing controllers or choose unique usernames for new accounts.
3974

4075
For session-based applications, users will see permissions organized into clear sections: an expandable "Authorize [game]" card containing contract methods, followed by dedicated spending limit cards for token approvals, making it easy to understand what they're authorizing.

0 commit comments

Comments
 (0)