2Authenticate users in the browser
Add a Personalization entry or Link trigger. It handles phone OTP and fires configure:linked with an agent-scoped token.
<script src="https://configure.dev/js/configure.js"></script>
<div id="configure-entry"></div>
<script>
Configure.personalizationButton({
el: '#configure-entry',
publishableKey: 'pk_your_publishable_key',
agent: 'your-agent',
agentName: 'Your Agent',
onImage: () => openImagePicker(),
onFile: () => openFilePicker()
});
document.addEventListener('configure:linked', (e) => {
const { token } = e.detail;
fetch('/api/configure/session', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ token })
});
});
</script>
3Use the profile server-side
Send the Link token to your backend. Read the approved profile there, pass formatted profile context to the model, expose Configure tools, and commit after read-backed turns.
import { Configure, toOpenAIFunctions } from 'configure';
const configure = new Configure({
apiKey: process.env.CONFIGURE_API_KEY,
agent: process.env.CONFIGURE_AGENT
});
app.post('/api/configure/session', requireUser, (req, res) => {
const { token } = req.body;
if (!token) return res.status(400).json({ error: 'missing_token' });
req.session.configureToken = token;
res.sendStatus(204);
});
app.post('/api/chat', async (req, res) => {
const { messages } = req.body;
const token = req.session.configureToken || req.body.token;
if (!token) return res.status(401).json({ error: 'configure_not_linked' });
const profile = configure.profile({ token });
const read = await profile.read();
const response = await model.run({
messages: [
{ role: 'system', content: read.profile.format({ guidelines: true }) },
...messages
],
tools: toOpenAIFunctions(profile.tools()),
executeTool: profile.executeTool
});
await profile.commit({ messages, response });
res.json({ text: response.text });
});