Authentication
N.U.T.S. tokens, session scoping, and self-hosted deployments.
Token shapes
Three kinds of tokens, one auth backend at auth.nuts.services:
| Token | Shape | Lifetime | Use |
|---|---|---|---|
| Browser JWT | eyJ... (3-part) | 24 hours | Browser login flow |
| API token | ahp_<opaque> | 1 year | Scripts, agents, MCP clients |
| Internal HMAC | <b64>.<b64> | seconds | Pre-signed query-string URLs only |
Browser login (web apps)
Redirect users to auth.nuts.services/login with a return_url pointing back to your service. Magic-link, Google, and GitHub are all supported.
- Send the user to:
https://auth.nuts.services/login?return_url=https://grub.nuts.services/auth/callback - User signs in via email magic-link, Google, or GitHub.
- Auth redirects back to your
return_urlwith the JWT in the query:https://grub.nuts.services/auth/callback?token=eyJ... - Stash the token (usually in
localStorage.nuts_session_token) and use it as the Bearer header for subsequent API calls.
Minimal JS — drop it in any page on your domain:
// Send users to login
function login() {
const returnUrl = encodeURIComponent(window.location.origin + '/auth/callback');
window.location.href = `https://auth.nuts.services/login?return_url=${returnUrl}`;
}
// On your /auth/callback page
const token = new URLSearchParams(location.search).get('token');
if (token) {
localStorage.setItem('nuts_session_token', token);
history.replaceState({}, '', '/dashboard');
}
Cross-origin tip: localStorage is per-origin. To open the auth.nuts.services dashboard from grub.nuts.services without forcing a re-login, append your JWT to the URL: https://auth.nuts.services/dashboard?token=<your-jwt>. The auth dashboard auto-captures it into its own localStorage.
ahp_ API tokens (backend / agents)
For scripts, AI agents, and MCP clients use long-lived ahp_ tokens. Generate from the auth dashboard → "New Token". Pass as the Bearer header on every request:
curl -X POST https://grub.nuts.services/api/crawl \
-H "Authorization: Bearer ahp_yourtoken" \
-H "Content-Type: application/json" \
-d '{"url": "https://example.com"}'
GrubCrawler validates tokens by routing them based on shape: 3-part dot-separated → GET auth.nuts.services/api/verify for JWT verification; ahp_-prefixed → POST auth.nuts.services/auth for exchange. Either way, your email is extracted from the verified claims and becomes the storage partition key — all your crawl results are stored under your account.
Self-hosted: disabling auth
If you're running GrubCrawler on a private network or internal cluster, you can disable token validation entirely:
docker run -p 8766:6792 -e DISABLE_AUTH=true deepbluedynamics/grubcrawler
With auth disabled, pass customer_id in every request body to scope storage:
{
"url": "https://example.com",
"customer_id": "my-agent-001"
}
Do not expose DISABLE_AUTH=true instances to the public internet. There is no rate limiting or access control when auth is disabled.
Session scoping
Sessions group related crawls. Pass a session_id to keep results together:
{
"url": "https://example.com",
"session_id": "research-run-2026-04-21",
"customer_id": "my-agent"
}
Retrieve all files for a session:
GET /api/sessions/{session_id}/files?customer_id=my-agent
AHP internal tokens
The GET /{tool_name}?bearer_token=... catch-all route uses short-lived HMAC tokens for internal tool-call dispatch. These are generated internally and are not for external use.
Get your N.U.T.S. API token at nuts.services. One token works across all N.U.T.S. services.