Public Keys + JWT
Public keys with JWT authentication enable secure, client-side access to the Enconvert API from browser environments. Because a public key is visible to end users, it cannot be used to call the API directly. Instead, it is exchanged for a short-lived JWT token that authorizes requests.
How It Works
- Exchange your public key (
pk_) for a JWT access token by callingPOST /v1/auth/token. - Use the JWT token in the
Authorization: Bearer <token>header on API requests. - Refresh the token automatically before it expires using
POST /v1/auth/refresh. - Domain whitelisting ensures that only requests originating from your approved domains are accepted.
Step 1: Exchange Public Key for JWT
Send your public key and the parent origin to obtain an access token.
Endpoint
POST /v1/auth/token
Request Headers
| Header | Value | Description |
|---|---|---|
X-API-Key |
pk_your_public_key |
Your public API key |
X-Parent-Origin |
https://yourdomain.com |
The origin of the parent page embedding the widget or making the request. Must match a whitelisted domain. |
JavaScript Example
async function getToken() {
const response = await fetch("https://api.enconvert.com/v1/auth/token", {
method: "POST",
headers: {
"X-API-Key": "pk_your_public_key",
"X-Parent-Origin": window.location.origin,
},
credentials: "include",
});
if (!response.ok) {
throw new Error(`Token exchange failed: ${response.status}`);
}
const data = await response.json();
return data.token;
}
credentials: "include" in the fetch options. This ensures the refresh token cookie is stored by the browser, which is required for automatic token refresh.
Response
{
"token": "eyJhbGciOiJIUzI1NiIs..."
}
The response also sets an HttpOnly cookie containing the refresh token. This cookie is managed automatically by the browser and is used when refreshing the access token.
Step 2: Use the JWT Token
Include the JWT token in the Authorization header as a Bearer token on all subsequent API requests.
async function convertUrlToPdf(token, url) {
const response = await fetch("https://api.enconvert.com/v1/convert/url-to-pdf", {
method: "POST",
headers: {
"Authorization": `Bearer ${token}`,
"Content-Type": "application/json",
},
body: JSON.stringify({ url }),
});
return await response.json();
}
// Usage
const token = await getToken();
const result = await convertUrlToPdf(token, "https://example.com");
console.log(result.presigned_url);
Step 3: Automatic Token Refresh
Access tokens expire after a short period. Use the refresh endpoint to obtain a new access token without requiring the user to re-authenticate.
Endpoint
POST /v1/auth/refresh
The refresh token is sent automatically via the HttpOnly cookie that was set during the initial token exchange. No request body or additional headers are needed.
JavaScript Auto-Refresh Example
class EnconvertClient {
constructor(publicKey) {
this.publicKey = publicKey;
this.token = null;
this.tokenExpiry = null;
}
async getToken() {
const response = await fetch("https://api.enconvert.com/v1/auth/token", {
method: "POST",
headers: {
"X-API-Key": this.publicKey,
"X-Parent-Origin": window.location.origin,
},
credentials: "include",
});
const data = await response.json();
this.token = data.token;
// Set expiry to 55 minutes (refresh before the 1-hour expiry)
this.tokenExpiry = Date.now() + 55 * 60 * 1000;
return this.token;
}
async refreshToken() {
const response = await fetch("https://api.enconvert.com/v1/auth/refresh", {
method: "POST",
credentials: "include",
});
if (!response.ok) {
// Refresh token expired, re-authenticate
return await this.getToken();
}
const data = await response.json();
this.token = data.token;
this.tokenExpiry = Date.now() + 55 * 60 * 1000;
return this.token;
}
async getValidToken() {
if (!this.token || Date.now() >= this.tokenExpiry) {
if (this.token) {
return await this.refreshToken();
}
return await this.getToken();
}
return this.token;
}
async convert(endpoint, body) {
const token = await this.getValidToken();
const response = await fetch(`https://api.enconvert.com${endpoint}`, {
method: "POST",
headers: {
"Authorization": `Bearer ${token}`,
"Content-Type": "application/json",
},
body: JSON.stringify(body),
});
return await response.json();
}
}
// Usage
const client = new EnconvertClient("pk_your_public_key");
const result = await client.convert("/v1/convert/url-to-pdf", {
url: "https://example.com",
});
Token Lifetimes
| Token | Lifetime | Storage |
|---|---|---|
| Access token | 1 hour | Returned in the JSON response body; store in memory |
| Refresh token | 7 days | Set as an HttpOnly cookie; managed by the browser |
Domain Whitelisting
Public keys are restricted to specific domains configured in your dashboard. The X-Parent-Origin header sent during the token exchange must match one of your whitelisted domains.
Matching Rules
- Exact match:
https://example.commatches onlyhttps://example.com. - Wildcard subdomains:
https://*.example.commatcheshttps://app.example.com,https://staging.example.com, etc. - Port-specific:
http://localhost:3000matches only that exact origin including the port.
Examples
| Whitelisted Domain | Matches | Does Not Match |
|---|---|---|
https://example.com |
https://example.com |
https://www.example.com |
https://*.example.com |
https://app.example.com, https://dev.example.com |
https://example.com |
http://localhost:3000 |
http://localhost:3000 |
http://localhost:8080 |
Security Features
- Short-lived tokens: Access tokens expire after 1 hour, limiting the window of exposure if a token is compromised.
- HttpOnly refresh cookies: Refresh tokens are stored in
HttpOnlycookies, making them inaccessible to JavaScript and resistant to XSS attacks. - Domain restrictions: Tokens are only issued when the request originates from a whitelisted domain.
- Origin validation: The API validates both the
OriginandX-Parent-Originheaders to prevent unauthorized cross-origin requests. - No direct API access: Public keys alone cannot call conversion endpoints. A valid JWT is always required.
Public Key Restrictions
Public key authentication has the following limitations compared to private keys:
- Synchronous only: Only synchronous conversion endpoints are available. Async operations, job polling, and webhooks are not supported.
- Single URL per request: Batch processing is not available. Each request may convert only one URL or file.
- Direct download: Responses provide a
presigned_urlfor immediate download. There is no option for custom storage destinations.
Verify Authentication
Use the verify endpoint to check whether your current authentication (private key or JWT) is valid.
Endpoint
GET /v1/auth/verify
Example
curl https://api.enconvert.com/v1/auth/verify \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..."
Response (Valid)
{
"authenticated": true,
"key_type": "public",
"user_id": "12345"
}
Response (Invalid)
{
"authenticated": false,
"error": "Token expired or invalid"
}
- Always store access tokens in memory only. Never persist them to
localStorageorsessionStorage. - Implement automatic token refresh to avoid interruptions during user sessions.
- Keep your whitelisted domains list as specific as possible. Avoid broad wildcards.
- Use
credentials: "include"on all fetch requests to ensure cookies are sent and received correctly. - Handle token refresh failures gracefully by falling back to a full re-authentication with the public key.