Developers
Four steps
to connect your product
Sign a token for each user, import your OpenAPI file, label your actions, then add the assistant to your web app with one script tag.
Step 1
Sign tokens
on your backend
Orrin never sees your users’ passwords or sessions. Your backend signs a short lived token for the signed in user with your workspace’s private key, and the assistant checks it on every request: the signature against your active keys, the audience, the expiry and the fifteen minute limit.
Token claims
- kid
- Header. The key id shown in the console when you generated the key
- sub
- The user’s id in your system. Required
- aud
- orrin. Required
- iat, exp
- Required. exp at most fifteen minutes after iat
- scopes
- What the user may do, as an array or a space separated string
- role
- The user’s role in your product, shown when a preview is refused
- company
- The customer company the user belongs to. Optional
// Node with jose. Your route, behind your own sign in. The token lives ten minutes.
import { SignJWT, importPKCS8 } from "jose";
const privateKey = await importPKCS8(process.env.ORRIN_PRIVATE_KEY, "EdDSA");
app.get("/api/orrin-token", requireSession, async (req, res) => {
const token = await new SignJWT({ company: req.user.companyId, role: req.user.role, scopes: req.user.scopes })
.setProtectedHeader({ alg: "EdDSA", kid: ORRIN_KEY_ID })
.setSubject(req.user.id)
.setAudience("orrin")
.setIssuedAt()
.setExpirationTime("10m")
.sign(privateKey);
res.type("text/plain").send(token);
});# FastAPI with PyJWT (pip install pyjwt cryptography). The token lives ten minutes.
import time
import jwt
@app.get("/api/orrin-token", response_class=PlainTextResponse)
def orrin_token(user: User = Depends(current_user)):
now = int(time.time())
claims = {"sub": str(user.id), "company": user.company_id, "role": user.role, "scopes": user.scopes,
"iat": now, "exp": now + 600, "aud": "orrin"}
return jwt.encode(claims, ORRIN_PRIVATE_KEY, algorithm="EdDSA", headers={"kid": ORRIN_KEY_ID})Step 2
Import
your OpenAPI file
Upload or link your OpenAPI specification in the console. Each endpoint becomes a candidate tool with a name, a description and typed parameters taken from your schema. Nothing is exposed until you choose it.
Step 3
Label
your actions
Mark each exposed endpoint Read, Write or Sensitive and try a preview in the console. In your product, a preview is prepared only when the user’s scopes cover the operation: resource:read for a Read operation, resource:write for Write and Sensitive, where the resource is the first segment of its path. POST /work-orders needs work_orders:write, and *:read or *:write cover every resource.
Step 4
Add the assistant
to your product
Two tags put a button in the corner of your web app that opens the assistant in a panel. The panel asks your page for the user’s token through orrinSettings.getToken, answers from your documentation with citations and previews actions within the user’s scopes. It loads only on the origins you approved in the console, and your workspace id is on its Embed and theme page.
<!-- On every page where signed in users should see the assistant -->
<script src="https://orrin.live/embed.js" data-workspace="YOUR_WORKSPACE_ID" defer></script>
<script>
window.orrinSettings = {
// Called whenever the assistant needs a token: return the one your route signs.
getToken: () => fetch("/api/orrin-token").then((response) => response.text()),
};
</script>// Optional, once the page has loaded
window.Orrin.open(); // also .close() and .toggle()
// Optional attributes on the script tag
// data-label="Help" the button text (default "Ask")
// data-position="left" the corner it sits in (default right)
// data-accent="#1f6f5c" the button colour until your workspace's accent loadsSupport
Help when
you need it
Every workspace reaches the Orrin team from Contact Orrin in the console, and the articles cover what to prepare before you connect your product.