You want to help build a Telegram auth plugin. Telegram, the platform where bots talk to bots about talking to bots. Sounds about right. Come on in.
git clone https://github.com/vcode-sh/better-auth-telegram.git
cd better-auth-telegram
npm install- Node.js >= 24 (see
.nvmrc-- yes, I pinned it, I'm not an animal) - npm 11.18.0 (the version used in CI)
These are the incantations. Learn them. Love them. Run them before pushing.
npm run dev # Watch mode build (tsdown) -- for the impatient
npm run build # Production build (tsdown: ESM + CJS + DTS, checked by publint + attw) -- the real thing
npm run type-check # TypeScript strict check -- the compiler judges you so I don't have to
npm run test:types # Type-check a consumer of the built dist/ (run build first)
npm test # Run all tests -- you'd be surprised how many people skip this
npm run test:watch # Watch mode -- for when you're in the zone
npm run test:ui # Vitest UI -- pretty graphs that prove you did something
npm run test:coverage # Coverage report -- inspect gaps; do not optimize the number
npm run test:adapters # Real PostgreSQL / MySQL / MongoDB (Docker); databases without a BAT_TEST_*_URL are skipped, see vitest.adapters.config.ts
npm run lint # Biome lint check -- it has opinions and they are correct
npm run lint:fix # Auto-fix -- let the machine do the boring partsrc/
index.ts Public server plugin entry
client.ts Public client plugin entry and API actions
client-widget.ts Browser widget lifecycle and widget option types
client-types.ts Client response and user types
plugin-config.ts Option parsing, defaults, startup warnings
schema.ts Conditional user/account schema fields
widget-endpoints.ts /telegram/signin, /telegram/link, /telegram/unlink
miniapp-endpoints.ts /telegram/miniapp/signin, /telegram/miniapp/validate
config-endpoint.ts /telegram/config
telegram-account.ts Find-or-create orchestration
telegram-account-state.ts Shared account types, lookups, validation and locks
telegram-account-user.ts User provisioning and returning-user refresh
telegram-account-link.ts Explicit account link/unlink
telegram-session.ts Session creation and cookie refresh
oidc.ts Telegram OIDC provider factory
oidc-token.ts JWKS/token verification and claim normalization
oidc-linking.ts Match verified identity before OIDC account lookup
oidc-linking-policy.ts Linked identity proof and application validation
telegram-identity.ts Database hook registration
telegram-identity-state.ts Verified request claims and changed-user tracking
telegram-identity-sync.ts Copy/reconcile identity on users and accounts
telegram-identity-session.ts OIDC session-cookie refresh
telegram-profile.ts Mapped profile updates
telegram-placeholder.ts Placeholder reservation and OIDC email selection
verify.ts HMAC-SHA256 verification via Web Crypto API
types.ts Public server types
constants.ts Error codes, defaults, provider IDs and endpoints
testing/harness.ts Stable imports for shared test fixtures
testing/auth.ts Real Better Auth on memory or SQLite
testing/http-client.ts Cookie-aware test client
testing/signed-data.ts Signed Widget and Mini App fixtures
testing/oidc-server.ts Fake oauth.telegram.org server
testing/oidc-flow.ts OIDC claims and complete sign-in helpers
testing/constants.ts Independent fixture constants
testing/adapters.ts Real database adapter fixtures
*.test.ts Co-located unit tests
*.integration.test.ts Tests against a real Better Auth instance
test-d/ Type tests for consumers of dist/
The package still exposes only better-auth-telegram and better-auth-telegram/client. Supporting modules are internal; consumers should not import their paths.
Not guidelines. Not suggestions. Rules.
- Tests live next to their code as
*.test.ts-- no hunting through a distant__tests__folder like it's 2017 - Run
npm run lint:fixbefore committing -- Biome catches things your eyes won't - All tests must pass with
npm test-- a failing test suite is not a "known issue," it's a blocker - Type safety everywhere -- no
anyat public API boundaries, this isn't JavaScript - Security first, features second -- validate inputs, verify signatures, no shortcuts
- Async verification only -- all crypto goes through
crypto.subtle, no synchronousnode:crypto - Use
APIErrorfrombetter-auth/api-- rawctx.json({ error })died in v0.4.0, let it rest - Write users and accounts through
ctx.context.internalAdapter-- rawctx.context.adapter.createskipsdatabaseHooksanduser.validateUserInfo, which is exactly the v2 bug v3 fixed. Reads viaadapter.findOneare fine - Update CHANGELOG.md for user-facing changes -- the changelog is a love letter to your future maintainers
Use Testing standards to find the shared testing-patterns skill and repository guidance for writing, reviewing and pruning tests.
- Verification: crypto tests in
verify.test.tsandverify-hardening.test.ts-- HMAC paths, replay attacks, futureauth_date, hash format, edge cases - Server plugin:
widget.integration.test.ts,miniapp.integration.test.tsandwidget-mappers.integration.test.tscover Widget/Mini App sign-in, account changes and mapping. OIDC suites are grouped by behavior:oidc.integration.test.ts,oidc-protocol.integration.test.ts,oidc-identity.integration.test.ts,oidc-profile.integration.test.ts,oidc-claims.integration.test.tsandoidc-linking.integration.test.ts.identity.integration.test.tsandhooks.integration.test.tscover revocation, placeholders and application hooks. These use realbetterAuth()instances (memory or SQLite) and a fake Telegram modeled on the live one. Prefer them over mocking Better Auth: mock-only tests passed while OIDC was broken on 1.7 - Client plugin: exercise widget behavior through the DOM and session refresh through the real Better Auth client store. Control the external HTTP/script boundary; do not replace the behavior being tested.
- Security: adversarial inputs, timestamp manipulation, malformed data, forged ID tokens
- Fork the repo and branch off
main(notdevelop, notfeature-branch-from-six-months-ago) - Add or strengthen tests only for changed behavior or a concrete uncovered risk; follow Testing standards.
- Make sure absolutely everything passes:
npm run type-check && npm test && npm run lint
- Update documentation if applicable (it is applicable more often than you think)
- Update
CHANGELOG.mdunder an[Unreleased]section - Open a PR with a clear description -- "misc fixes" tells me nothing
- Bugs: use the bug report template
- Features: use the feature request template
- Security: see SECURITY.md -- do NOT open a public issue for vulnerabilities unless you enjoy chaos
There is one. It's in CODE_OF_CONDUCT.md. The short version: don't be awful. The long version: read the file.
Node.js 24 is the minimum. The required CI check collects package validation, Node 24.0.0 and current 24/26 tests, the complete Better Auth 1.7.17 family, forced Bun 1.4.4 tests and real database adapters. A failed or skipped required lane fails the gate. Fork PRs run with read-only permissions.
npm run build checks the bundles and declarations with publint and Are The Types Wrong. npm run test:package packs the result, installs it outside the checkout, checks its consumer types, exercises ESM authentication configuration and loads both CommonJS exports. It leaves better-auth-telegram-<version>.tgz for inspection. CI uploads that tarball.
A matching v<version> tag on a commit belonging to main runs the same CI before release. Only the separate publisher receives npm OIDC permission; it publishes the validated tarball with provenance, without rebuilding or running lifecycle scripts. Stable versions use latest, prereleases use next. Creating a PR does not publish a release.
Codecov uses the same 90% coverage floor as Vitest. Coverage is a guardrail; add tests that challenge observable behavior rather than tests whose only purpose is reaching 100%.