- Implement PKCE (Proof Key for Code Exchange) with S256 method - Add crypto/pkce module with code verifier and challenge generation - Modify OAuth flow to include code_challenge in authorization requests - Update HandleCallback to validate code_verifier during token exchange - Extend session lifetime from 7 to 30 days - Add comprehensive unit tests for PKCE functions - Maintain backward compatibility with fallback for non-PKCE sessions - Add detailed logging for OAuth flow with PKCE tracking PKCE enhances security by preventing authorization code interception attacks, as recommended by OAuth 2.1 and OIDC standards. feat: add encrypted refresh token storage with automatic cleanup - Add oauth_sessions table for storing encrypted refresh tokens - Implement AES-256-GCM encryption for refresh tokens using cookie secret - Create OAuth session repository with full CRUD operations - Add SessionWorker for automatic cleanup of expired sessions - Configure cleanup to run every 24h for sessions older than 37 days - Modify OAuth flow to store refresh tokens after successful authentication - Track client IP and user agent for session security validation - Link OAuth sessions to user sessions via session ID - Add comprehensive encryption tests with security validations - Integrate SessionWorker into server lifecycle with graceful shutdown This enables persistent OAuth sessions with secure token storage, reducing the need for frequent re-authentication from 7 to 30 days.
7.4 KiB
Embedding & Integrations
Integrate Ackify into your tools (Notion, Outline, Google Docs, etc.).
Integration Methods
1. Direct Link
The simplest:
https://sign.company.com/?doc=policy_2025
Usage:
- Chat (Slack, Teams)
- Wiki
- Documentation
Behavior:
- User clicks → Arrives at signature page
- Logs in via OAuth2
- Signs the document
2. iFrame Embed
To integrate in a web page:
<iframe src="https://sign.company.com/?doc=policy_2025"
width="600"
height="200"
frameborder="0"
style="border: 1px solid #ddd; border-radius: 6px;">
</iframe>
Render:
┌─────────────────────────────────────┐
│ 📄 Security Policy 2025 │
│ 42 confirmations │
│ [Sign this document] │
└─────────────────────────────────────┘
3. oEmbed (Auto-discovery)
For platforms supporting oEmbed (Notion, Outline, Confluence, etc.).
How it works
-
Paste URL in your editor:
https://sign.company.com/?doc=policy_2025 -
Editor auto-detects via meta tag:
<link rel="alternate" type="application/json+oembed" href="https://sign.company.com/oembed?url=..." /> -
Editor calls
/oembedand receives:{ "type": "rich", "version": "1.0", "title": "Security Policy 2025 - 42 confirmations", "provider_name": "Ackify", "html": "<iframe src=\"https://sign.company.com/?doc=policy_2025\" ...>", "height": 200 } -
Editor displays iframe automatically
Supported Platforms
- ✅ Notion - Paste URL → Auto-embed
- ✅ Outline - Paste URL → Auto-embed
- ✅ Confluence - oEmbed macro
- ✅ AppFlowy - URL unfurling
- ✅ Slack - Link unfurling (Open Graph)
- ✅ Microsoft Teams - Card preview
- ✅ Discord - Rich embed
Open Graph & Twitter Cards
Ackify automatically generates meta tags for previews:
<!-- Auto-generated for /?doc=policy_2025 -->
<meta property="og:title" content="Security Policy 2025 - 42 confirmations" />
<meta property="og:description" content="42 people confirmed reading the document" />
<meta property="og:url" content="https://sign.company.com/?doc=policy_2025" />
<meta property="og:type" content="website" />
<meta name="twitter:card" content="summary" />
Result in Slack/Teams:
┌─────────────────────────────────────┐
│ 🔐 Ackify │
│ Security Policy 2025 │
│ 42 confirmations │
│ sign.company.com │
└─────────────────────────────────────┘
Specific Integrations
Notion
-
Paste URL in a Notion page:
https://sign.company.com/?doc=policy_2025 -
Notion auto-detects oEmbed
-
Widget appears with signature button
Alternative: Create manual embed
/embed→ Paste URL
Outline
-
In an Outline document, paste:
https://sign.company.com/?doc=policy_2025 -
Outline automatically loads the widget
Google Docs
Google Docs doesn't support iframes directly, but:
-
Option 1 - Link:
Please sign: https://sign.company.com/?doc=policy_2025 -
Option 2 - Image Badge:
 -
Option 3 - Google Sites:
- Create a Google Sites page
- Insert iframe
- Link from Google Docs
See docs/integrations/google-doc/ for more details.
Confluence
- Edit a Confluence page
- Insert "oEmbed" or "HTML Embed" macro
- Paste:
https://sign.company.com/?doc=policy_2025
Slack
Link Unfurling:
-
Post URL in a channel:
Hey team, please sign: https://sign.company.com/?doc=policy_2025 -
Slack automatically displays preview (Open Graph)
Slash Command (future):
/ackify sign policy_2025
Microsoft Teams
- Post URL in a conversation
- Teams displays card preview (Open Graph)
PNG Badge
Generate a visual badge for README, wiki, etc.
Badge URL
https://sign.company.com/badge/policy_2025.png
Render:
Markdown
[](https://sign.company.com/?doc=policy_2025)
HTML
<a href="https://sign.company.com/?doc=policy_2025">
<img src="https://sign.company.com/badge/policy_2025.png" alt="Signature status">
</a>
oEmbed API
Endpoint
GET /oembed?url=https://sign.company.com/?doc=policy_2025
Response:
{
"type": "rich",
"version": "1.0",
"title": "Document policy_2025 - 42 confirmations",
"provider_name": "Ackify",
"provider_url": "https://sign.company.com",
"html": "<iframe src=\"https://sign.company.com/?doc=policy_2025\" width=\"100%\" height=\"200\" frameborder=\"0\" style=\"border: 1px solid #ddd; border-radius: 6px;\" allowtransparency=\"true\"></iframe>",
"width": null,
"height": 200
}
Parameters
| Parameter | Description | Example |
|---|---|---|
url |
Document URL (required) | ?url=https://... |
maxwidth |
Max width (optional) | ?maxwidth=800 |
maxheight |
Max height (optional) | ?maxheight=300 |
Discovery
All pages include discovery tag:
<link rel="alternate"
type="application/json+oembed"
href="https://sign.company.com/oembed?url=..."
title="Document title" />
Customization
Dark Mode Theme
Widget automatically detects browser's dark mode:
@media (prefers-color-scheme: dark) {
/* Automatic dark theme */
}
Custom Size
<iframe src="https://sign.company.com/?doc=policy_2025"
width="800"
height="300"
frameborder="0">
</iframe>
Language
Widget automatically detects browser language:
fr- Françaisen- Englishes- Españolde- Deutschit- Italiano
Security
iFrame Sandboxing
By default, Ackify iframes allow:
allow-same-origin- OAuth2 cookiesallow-scripts- Vue.js featuresallow-forms- Signature submissionallow-popups- OAuth redirect
CORS
Ackify automatically configures CORS for:
- All origins (public reading)
- Credentials via
Access-Control-Allow-Credentials
CSP
Content Security Policy headers configured to allow embedding:
X-Frame-Options: SAMEORIGIN
Content-Security-Policy: frame-ancestors 'self' https://notion.so https://outline.com
Troubleshooting
iframe not displaying
Verify:
- HTTPS enabled (required for OAuth)
- CSP headers allow embedding
- No content blocker (uBlock, Privacy Badger)
oEmbed not detected
Verify:
- Tag
<link rel="alternate" type="application/json+oembed">is present - URL is exact (with
?doc=...) - Platform supports oEmbed discovery
Slack preview empty
Verify:
- Open Graph meta tags present
- URL publicly accessible
- No infinite redirect
Complete Examples
See:
- docs/integrations/google-doc/ - Google Workspace integration
- More examples coming...