Comick Developers
Comick Developers
Catalog APIMy appsBack to ComickBuild with Comick

Getting started

Register your appApp review
Backend quickstartBrowser quickstartMobile quickstart

API reference

OAuth referenceRefresh and disconnectLibrary APIErrors and limits
Quickstarts

Browser quickstart

Use a public client with PKCE, registered origins, and no client secret.

Register a public browser app, including the exact HTTPS callback URL. Your app's origin must match a registered callback origin for cross-origin token and library requests. Do not ship a client secret.

1. Start PKCE in the browser

Run this after the user presses “Connect Comick.” The Web Crypto API requires a secure context (HTTPS or localhost).

const clientId = "YOUR_PUBLIC_CLIENT_ID"
const redirectUri = "https://your-app.example/oauth/comick/callback"
const resource = "https://api.comick.dev/integrations/v1"
function base64url(bytes: Uint8Array): string {
  return btoa(String.fromCharCode(...bytes))
    .replace(/\+/g, "-")
    .replace(/\//g, "_")
    .replace(/=+$/, "")
}
const verifier = base64url(crypto.getRandomValues(new Uint8Array(32)))
const state = base64url(crypto.getRandomValues(new Uint8Array(32)))
const challenge = base64url(
  new Uint8Array(
    await crypto.subtle.digest("SHA-256", new TextEncoder().encode(verifier)),
  ),
)
sessionStorage.setItem(
  "comick.oauth.attempt",
  JSON.stringify({
    state,
    verifier,
    redirectUri,
    createdAt: Date.now(),
  }),
)
const authorize = new URL("https://comick.dev/api/auth/oauth2/authorize")
authorize.search = new URLSearchParams({
  response_type: "code",
  client_id: clientId,
  redirect_uri: redirectUri,
  scope: "library:read",
  resource,
  state,
  code_challenge: challenge,
  code_challenge_method: "S256",
}).toString()
location.assign(authorize.toString())

This example supports one pending attempt per tab. Start the flow and handle its callback in the same tab and origin.

2. Validate and exchange on your callback page

Use the same clientId and resource constants as above. This code runs only on your registered callback route.

const query = new URLSearchParams(location.search)
const stored = sessionStorage.getItem("comick.oauth.attempt")
sessionStorage.removeItem("comick.oauth.attempt")
history.replaceState(null, "", location.pathname)
const attempt = stored ? JSON.parse(stored) : null
if (
  !attempt ||
  query.getAll("state").length !== 1 ||
  query.get("state") !== attempt.state ||
  Date.now() - attempt.createdAt > 10 * 60_000
) {
  throw new Error("Invalid or expired authorization attempt")
}
if (query.has("error"))
  throw new Error("Comick connection was declined or failed")
if (query.getAll("code").length !== 1 || !query.get("code")) {
  throw new Error("Missing authorization code")
}
const response = await fetch("https://comick.dev/api/auth/oauth2/token", {
  method: "POST",
  credentials: "omit",
  headers: { "Content-Type": "application/x-www-form-urlencoded" },
  body: new URLSearchParams({
    grant_type: "authorization_code",
    client_id: clientId,
    code: query.get("code")!,
    redirect_uri: attempt.redirectUri,
    code_verifier: attempt.verifier,
    resource,
  }),
})
if (!response.ok) throw new Error(`Comick exchange failed: ${response.status}`)
const tokens = await response.json()

3. Read the user's library

const response = await fetch(
  "https://api.comick.dev/integrations/v1/me/library",
  {
    credentials: "omit",
    cache: "no-store",
    headers: { Authorization: `Bearer ${tokens.access_token}` },
  },
)
if (!response.ok) throw new Error(`Comick library failed: ${response.status}`)
const library = await response.json()

Keep tokens in memory and reconnect when needed. The example uses session storage only for the short-lived PKCE attempt, never for access or refresh tokens. Avoid persistent token storage in localStorage; use a trusted backend if you need synchronization after the browser closes.

For optional refresh, request offline_access and follow the rotation rules. Browser clients must handle declined offline consent and cannot assume a refresh token will be returned.

Backend quickstart

Connect a confidential server application using Authorization Code and PKCE.

Mobile quickstart

Connect a native mobile or desktop application through the system browser.

On this page

1. Start PKCE in the browser2. Validate and exchange on your callback page3. Read the user's library