Fork of vestigiumincaligne/polka + OIDC SSO (fork-local feature)
  • Go 71.9%
  • JavaScript 21.2%
  • CSS 5.6%
  • Python 0.8%
  • NSIS 0.2%
  • Other 0.2%
Find a file
Sergey Popov 1b1a683993
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
fix(oidc): authenticate to the token endpoint with HTTP Basic
RFC 6749 §2.3.1 requires confidential clients to send the id/secret as
a form-urlencoded Basic header; sending the secret only in the POST body
(client_secret_post) breaks against providers that pin the registered
token_endpoint_auth_method — Authelia rejected the exchange with
invalid_client when the client was registered with the default basic
method.

Both call sites (authorization_code exchange and refresh grant) now set
the Basic header; the form fields stay for providers that require the
post method. The fake IdP in the e2e test now validates the Basic
credentials, and the CI image tag bumps to v0.1.22-polka.2.
2026-10-07 23:45:18 +03:00
.github CI: report vitest failures as annotations and give tests CI-sized timeouts 2026-09-12 10:08:51 +03:00
cmd Book collections: curated lists matched against the library, bundled Wikipedia lists, optional Forbes.ru source 2026-08-29 12:28:20 +03:00
collections Book collections: curated lists matched against the library, bundled Wikipedia lists, optional Forbes.ru source 2026-08-29 12:28:20 +03:00
docs README: add home page screenshot 2026-06-10 23:15:35 +03:00
internal fix(oidc): authenticate to the token endpoint with HTTP Basic 2026-10-07 23:45:18 +03:00
packaging Ship 32-bit ARM binary + arm64 packages for Raspberry Pi 2026-06-14 23:47:32 +03:00
web feat(auth): OIDC single sign-on for the web UI 2026-09-27 10:28:04 +00:00
.dockerignore Polka v0.1.0 — self-hosted home e-book library 2026-06-10 22:51:15 +03:00
.gitignore Polka v0.1.0 — self-hosted home e-book library 2026-06-10 22:51:15 +03:00
.woodpecker.yml fix(oidc): authenticate to the token endpoint with HTTP Basic 2026-10-07 23:45:18 +03:00
docker-compose.yml Polka v0.1.0 — self-hosted home e-book library 2026-06-10 22:51:15 +03:00
Dockerfile Transcode JPEG XL covers to JPEG (Flibusta dumps) 2026-06-15 19:11:59 +03:00
go.mod Transcode JPEG XL covers to JPEG (Flibusta dumps) 2026-06-15 19:11:59 +03:00
go.sum Transcode JPEG XL covers to JPEG (Flibusta dumps) 2026-06-15 19:11:59 +03:00
LICENSE Polka v0.1.0 — self-hosted home e-book library 2026-06-10 22:51:15 +03:00
Makefile Transcode JPEG XL covers to JPEG (Flibusta dumps) 2026-06-15 19:11:59 +03:00
oidc_smoke.py feat(auth): strict role mirror + background re-sync for OIDC 2026-09-27 17:48:32 +00:00
README.md feat(auth): strict role mirror + background re-sync for OIDC 2026-09-27 17:48:32 +00:00

Polka

Your home e-book library — fast, private, and beautiful.

Polka (Russian for "bookshelf") is a self-hosted library for e-book collection. Point it at a folder of books — or import a huge .inpx catalog — and get a polished web interface with search, covers, annotations, an online reader, reading lists, ratings, recommendations, and an OPDS feed for every mobile reading app.

Polka home page — personal shelves with covers, search, and reading progress


Highlights

  • Built for big collections. A 690,000-book catalog imports in about a minute and stays instant to browse and search (SQLite + FTS5 under the hood).
  • Read in your browser. A clean, newspaper-style reader for FB2, EPUB and TXT with continuous scrolling, themes (light / sepia / dark), adjustable fonts, footnotes, live tables of contents, and per-user reading progress. PDF opens in a dedicated reader with the same progress tracking.
  • Find your next book. Personal shelves: Reading now, Want to read, Continue the series, and For you — recommendations scored from your ratings, lists, and reading history. Plus "similar books" on every book page, optionally enriched by external sources (FantLab, TasteDive).
  • Search everything. Titles, authors, series, genres — and ISBN: paste an ISBN in any format and Polka finds the book locally or resolves it via Open Library / Google Books.
  • Reading lists & ratings. Build custom lists, mark books you want to read, rate books 1–5 — average ratings are visible to everyone on your server. External ratings (LiveLib, Google Books, Open Library) can be enabled per source by the admin.
  • Curated collections. Well-known book lists — 100 Books of the Century (Le Monde), BBC's The Big Read, the Norwegian Book Club's 100 best books and more — ship with Polka and appear as home-page shelves showing which of the listed books you already have. Add your own as a JSON list of "author + title", or enable an external source (Forbes.ru book selections, polled daily; off by default). See collections/.
  • OPDS catalog. Connect Moon+ Reader, KOReader, FBReader, or any other OPDS-capable app: new books, browse by author, series and genre, your "reading now" shelf, and search.
  • E-ink reader progress sync. Polka speaks the KOReader sync protocol (kosync): KOReader on PocketBook, Kindle, Kobo, reMarkable and friends pushes the reading position straight to your server, and books read on the device show their progress on Polka's "Reading now" shelf. Each user sets a device password in the top-bar "E-reader" dialog.
  • Send to your e-reader. Configure SMTP once and e-mail any book straight to your Kindle / Kobo / PocketBook from its page (the SMTP password is stored encrypted).
  • Multi-user. Accounts with admin/reader roles, per-user progress, lists and ratings. Or run it fully open on a trusted home network.
  • Add books from the browser. Upload fb2 / epub / pdf / djvu / txt / mobi; metadata is extracted automatically and three-level duplicate detection (file hash → text hash → fuzzy metadata) keeps your collection clean.
  • Two languages. English and Russian UI, switchable in one click; genre names and the OPDS feed are localized too.
  • Mobile-friendly + PWA. Add Polka to your phone's home screen and it behaves like an app.
  • Desktop apps that don't need a server. Native-feel clients for Windows and Linux work fully standalone: your library, reader, lists and ratings live right on your machine — no server, no account, no internet required. Optionally connect them to your Polka server later and get two-way sync of progress, ratings, and lists, including offline copies of selected books.

Quick start

docker run -d --name polka \
  -p 12791:12791 \
  -v polka-data:/data \
  -v /path/to/your/books:/books \
  ghcr.io/vestigiumincaligne/polka:latest

Open http://localhost:12791, sign in with the bootstrap admin account (created on first run — see the container log: docker logs polka), and start exploring. Or use docker-compose.yml:

docker compose up -d

Desktop app — no server required

If you just want a personal library on one computer, skip the server entirely: install the desktop app from the releases page (polka-setup-<version>.exe on Windows, .deb/.rpm on Linux) and launch Polka. It opens in its own window, stores everything locally, and works offline. You can connect it to a server later at any time — nothing to reconfigure.

Prebuilt binaries and installers

Grab the latest release:

Platform What you get
Windows polka-setup-<version>.exe — installer for the desktop app (server included)
Linux .deb / .rpm packages (amd64, arm64), plus standalone binaries
Raspberry Pi 64-bit OS → polka-linux-arm64 (or the arm64 .deb / Docker); 32-bit OS → polka-linux-arm
Any polka server binary — single file, no dependencies

Run the server directly:

polka serve --library-dir /path/to/books

Build from source

Requires Go 1.26+ and Node 20+.

git clone https://github.com/vestigiumincaligne/polka
cd polka
make build        # builds web UI + bin/polka + bin/polka-desktop
./bin/polka serve --library-dir /path/to/books

Importing a large catalog

Polka understands .inpx index files (MyHomeLib / Flibusta format) — both from the command line and from the web UI (Manage → Import):

polka import --inpx collection.inpx --data-dir /path/to/data --library-dir /path/to/archives

You can also import an inpx that already sits on the server (e.g. a mounted or NFS collection) straight from the web UI — paste its path in Manage → Import instead of uploading. The book archives are looked up under --library-dir.

Book files may sit in plain folders or inside ZIP or 7z archives (the usual Flibusta layout, e.g. f.fb2-…​.7z) — Polka reads them directly, no unpacking needed.

Hundreds of thousands of records import in about a minute. Re-importing replaces the catalog but never touches user data — accounts, progress, ratings and lists live in a separate database and survive re-imports.

The desktop apps

polka-desktop opens Polka in its own window (WebView2 on Windows, Chromium app window on Linux) and can work two ways:

  • Standalone (default) — a personal library on your computer. No server, no sign-in, works completely offline.
  • Connected — point it at your Polka server (Server page in the app): the full catalog is available online, selected books are downloaded for offline reading, and progress / ratings / lists sync both ways automatically.

OPDS

Point your reading app at http://your-server:12791/opds — no converting or copying files, the books open straight on the device. Authentication is HTTP Basic with your Polka account. The catalog has new books, browse by author, by series, and by genre (alphabetical), search, and a personal "Reading now" feed; downloads work in fb2, zip, epub, and pdf. The admin can turn OPDS on or off and copy the connection address in Manage → OPDS.

E-ink readers (PocketBook, Kindle, Kobo…)

Install KOReader on the device, then:

  1. Books: add the OPDS catalog http://your-server:12791/opds (your Polka login and password) — browse, search and download right on the device. PocketBook owners can also use Polka's Send to e-reader button with their @pbsync.com address.
  2. Progress sync: in Polka's top bar open E-reader, set a device password; on the device: Tools → Progress sync, server address = your Polka URL, username = your Polka login, password = the device password. Positions of books downloaded through Polka then follow you between the device, the web reader and other KOReader devices.

Configuration

Everything has a sensible default. The most useful flags of polka serve:

Flag Default Meaning
--addr :12791 listen address
--data-dir ~/.polka database, settings, covers cache
--library-dir — folder with books (or inpx archives)
--auth users users (accounts) or none (open access)

OIDC single sign-on (fork addition)

This fork adds an OIDC Authorization Code flow for the web UI (this is a fork-local feature, not in upstream Polka). Configure via env:

Variable Meaning
POLKA_OIDC_ISSUER Issuer URL — enables SSO when set (e.g. https://auth.example.com)
POLKA_OIDC_CLIENT_ID Client ID registered at the provider
POLKA_OIDC_CLIENT_SECRET Client secret (omit for public clients)
POLKA_OIDC_REDIRECT_URL https://<polka-host>/auth/oidc/callback
POLKA_OIDC_SCOPES Defaults to openid profile email
POLKA_OIDC_ADMIN_GROUP Group claim value mapping: strict mirror — in the group = admin, not in the group = user (both promotion and demotion at login; a background re-sync applies the same rule to already-signed-in users). The last active administrator is never demoted.
POLKA_OIDC_PROVIDER_NAME Label on the login button (default SSO)
POLKA_OIDC_SYNC_INTERVAL Re-sync interval (Go duration, default 5m; negative disables the loop). Each round re-validates every OIDC user with a stored refresh token against the IdP and applies the strict role mirror — a deposed admin loses the role within one interval, without re-login.

Behaviour:

  • Discovery via /.well-known/openid-configuration (endpoints + PKCE support are resolved at startup). Works with Authelia, Keycloak, Dex, LLDAP's OIDC endpoint, etc.
  • Authorization Code flow with state + nonce bound to a short-lived HttpOnly cookie; PKCE S256 when the provider supports it.
  • The local account is linked to the IdP by the sub claim and JIT-provisioned on first sign-in (login from preferred_username / email local-part).
  • Strict role mirror: membership in POLKA_OIDC_ADMIN_GROUP is authoritative — in the group means admin, not in the group means user. Applied at every login and by a background re-sync loop (refresh grant → userinfo, default every 5 minutes) so a deposed admin loses the role quickly without re-logging in. The last active administrator is never demoted (same guard as local user management), and a failing IdP never takes the library down — the loop just skips that round.
  • Local password login stays available for the bootstrap admin; OPDS readers keep using HTTP Basic (SSO does not apply to Basic clients).

Tested against a mock provider in internal/server/oidc_e2e_test.go (full browser-style flow) and oidc_smoke.py (live binary + mock IdP).

External rating/recommendation sources are configured in the web UI (Manage → External ratings / Similar books) and are off by default except local recommendations — nothing is queried without the admin's consent.

Tech notes

  • Single Go binary; the React frontend is embedded at build time.
  • SQLite (pure-Go driver) with WAL and FTS5 — no database server to run.
  • User data (accounts, sessions, progress, ratings, lists) is stored separately from the catalog and survives re-imports; so do curated collections, which are re-matched against the catalog after every import.
  • Sync between desktop clients and the server is state-based with last-write-wins per record.

Support the project ❤️

Polka is free and MIT-licensed. If it made your library nicer, you can support development through the Sponsor button on this repository — it genuinely helps.

Bug reports and feature ideas are welcome in Issues.

License

MIT