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 |
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",
},
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.
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.
- 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.
- 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.