Loading...
Loading...
Add OAuth connections for 200+ platforms (Gmail, Slack, HubSpot, etc.) with Pica's drop-in AuthKit widget
npx skill4agent add picahq/skills authkit┌─────────────┐ ┌─────────────────┐ ┌─────────────┐
│ Frontend │────▶│ Your Backend │────▶│ Pica API │
│ (AuthKit) │ │ (Token Endpoint)│ │ │
└─────────────┘ └─────────────────┘ └─────────────┘
│ │
└───────────── OAuth Flow ──────────────────┘npm install @picahq/authkitnpm install @picahq/authkit-tokenimport { AuthKitToken } from "@picahq/authkit-token";
const authKitToken = new AuthKitToken(PICA_SECRET_KEY);
const token = await authKitToken.create({
identity: userId, // Your user's unique identifier
identityType: "user", // "user" | "team" | "organization" | "project"
});
// Return token directly
return token;| Type | Use Case |
|---|---|
| Personal connections per user |
| Shared connections within a team |
| Company-wide shared connections |
| Project-scoped isolated connections |
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: POST, OPTIONS
Access-Control-Allow-Headers: Content-Type, Authorization, x-user-idx-user-id{
"token": "akt_xxxxx...",
"expiresAt": "2024-01-01T00:00:00Z"
}import { useAuthKit } from "@picahq/authkit";
function ConnectButton() {
const { open, isLoading } = useAuthKit({
token: {
url: "https://your-domain.com/api/authkit/token", // MUST be full URL
headers: {
"x-user-id": currentUserId,
},
},
selectedConnection: "Gmail", // Optional: skip list, go directly to this integration
onSuccess: (connection) => {
// connection.key - unique identifier for this connection
// connection.platform - e.g., "gmail"
// connection.environment - "live" or "test"
// connection.state - "operational", "degraded", "failed", "unknown"
saveConnectionToDatabase(connection);
},
onError: (error) => {
console.error("Connection failed:", error);
},
onClose: () => {
console.log("Modal closed");
},
});
return (
<button onClick={() => open()} disabled={isLoading}>
Connect Integration
</button>
);
}// CORRECT - Full URL
url: "https://your-domain.com/api/authkit/token"
url: `${window.location.origin}/api/authkit/token`
// INCORRECT - Will fail
url: "/api/authkit/token"// Opens directly to Gmail auth flow
selectedConnection: "Gmail"
// Opens directly to Slack auth flow
selectedConnection: "Slack"
// Opens to integration list (user picks)
selectedConnection: undefinedonSuccessinterface Connection {
key: string; // "live::gmail::default::abc123" - use this for API calls
platform: string; // "gmail"
environment: string; // "live" or "test"
state: string; // "operational", "degraded", "failed", "unknown"
}CREATE TABLE user_connections (
id UUID PRIMARY KEY,
user_id TEXT NOT NULL, -- Your user identifier
platform TEXT NOT NULL, -- "gmail", "slack", etc.
connection_key TEXT UNIQUE, -- Pica connection key
environment TEXT DEFAULT 'live', -- "live" or "test"
state TEXT DEFAULT 'operational',
created_at TIMESTAMP DEFAULT NOW(),
updated_at TIMESTAMP DEFAULT NOW()
);onSuccess: async (connection) => {
await fetch("/api/connections", {
method: "POST",
body: JSON.stringify({
user_id: currentUserId,
platform: connection.platform,
connection_key: connection.key,
environment: connection.environment,
state: connection.state,
}),
});
refreshConnectionsList();
}GET https://api.picaos.com/v1/available-connectors?authkit=true&limit=300
Headers:
x-pica-secret: YOUR_PICA_SECRET_KEY{
"rows": [
{
"platform": "gmail",
"name": "Gmail",
"category": "Communication",
"image": "https://...",
"description": "..."
}
],
"total": 200,
"pages": 1,
"page": 1
}| Field | Description |
|---|---|
| Platform identifier (use for API calls) |
| Display name (use for |
| Category for grouping |
| Logo URL |
connection_keyPOST https://api.picaos.com/v1/passthrough/{platform}/{action}
Headers:
x-pica-secret: YOUR_PICA_SECRET_KEY
x-pica-connection-key: CONNECTION_KEY_FROM_DATABASE
Content-Type: application/jsonconst response = await fetch(
"https://api.picaos.com/v1/passthrough/gmail/messages/send",
{
method: "POST",
headers: {
"x-pica-secret": PICA_SECRET_KEY,
"x-pica-connection-key": user.gmailConnectionKey,
"Content-Type": "application/json",
},
body: JSON.stringify({
to: "recipient@example.com",
subject: "Hello",
body: "Message content",
}),
}
);chrome://flags| Issue | Cause | Solution |
|---|---|---|
| 405 Method Not Allowed | Missing OPTIONS handler | Add OPTIONS endpoint with CORS headers |
| CORS error | Missing or wrong CORS headers | Include all custom headers in Access-Control-Allow-Headers |
| Token fetch fails | Invalid PICA_SECRET_KEY | Verify key at app.picaos.com/settings/api-keys |
| Opens list instead of integration | Wrong selectedConnection value | Use display name ("Gmail") not platform ID ("gmail") |
| Connection not saving | onSuccess not storing data | Save connection in onSuccess callback |
| Foreign key error | user_id references non-existent user | Remove foreign key constraint or ensure user exists |
import { AuthKitToken } from "@picahq/authkit-token";
const token = new AuthKitToken(secretKey);
await token.create({ identity, identityType });import { useAuthKit } from "@picahq/authkit";
const { open, isLoading } = useAuthKit({ token, onSuccess, onError, onClose, selectedConnection });GET /v1/available-connectors?authkit=trueGET /v1/vault/connections?identity={id}&identityType=userPOST /v1/passthrough/{platform}/{action}