Releases: vcode-sh/better-auth-telegram
Release list
v2.0.1
v2.0.0
v1.5.0
What's new
loginWidget option (#16)
loginWidget?: boolean (default true). Set to false to disable Login Widget endpoints and omit Telegram-specific schema fields. OIDC-only setups no longer get 5 unused database columns cluttering their schema.
telegram({
botToken: "...",
botUsername: "...",
loginWidget: false,
oidc: { enabled: true, clientSecret: "..." },
})Zero breaking changes — undefined defaults to true.
Modular refactoring
src/index.ts (747 LOC monolith) split into 6 focused modules. Same public API, same behaviour, now actually maintainable.
| File | Purpose |
|---|---|
plugin-config.ts |
Config parsing + validation |
schema.ts |
Conditional user/account fields |
config-endpoint.ts |
GET /telegram/config |
widget-endpoints.ts |
signIn, link, unlink |
miniapp-endpoints.ts |
Mini App signIn, validate |
index.ts |
Thin orchestrator (~85 LOC) |
Tests
261 → 329 tests. 100% statement/line/function coverage. Every branch in every extracted module exercised.
Also
loginWidgetEnabledin config response- Rate limits now conditional (only registered when the corresponding flow is active)
- Fixed incorrect cross-provider comments in endpoint handlers
npm install better-auth-telegram@1.5.0
Full Changelog: v1.4.0...v1.5.0
v1.4.0
OIDC actually works now
Full OAuth 2.0 Authorization Code flow with PKCE — tested end-to-end, consent screen to dashboard. The whole thing.
Fixed
- OIDC
invalid_clientresolved (#11) — The Client Secret is NOT the bot token. BotFather provides a separate secret via Bot Settings > Web Login. Removed non-standardoriginandbot_idparams from the auth URL. Clean standard OIDC now. - OIDC cross-domain redirect (#12) —
originwas derived from the backendredirectURI, breaking setups where frontend and backend live on different domains. Telegram redirected toapi.example.com/#tgAuthResult=...instead ofredirect_uri?code=.... Removedoriginentirely — Telegram uses the standardredirect_urinow. - Login Widget / Mini App P2002 crash (#13) —
/telegram/signinand/telegram/miniapp/signincrashed withUnique constraint failed on emailwhen the user already existed via OIDC. Now checks for existing users bytelegramIdbefore attempting creation. Links the account instead of creating a duplicate.
Added
oidc.clientSecretoption — Pass the Client Secret from BotFather's Web Login settings. Falls back to bot token with a warning if omitted, but OIDC won't work without the proper secret.- Step-by-step OIDC setup docs — Including the undocumented BotFather "remove URL, reopen, switch to OpenID Connect Login" ritual.
Changed
- Test count: 225 → 235. Nine new tests for cross-provider account linking and auth URL regression guards. All verified as failing against v1.3.x.
Migration from v1.3.x
- OIDC users: Add
oidc.clientSecretfrom BotFather's Web Login settings (Bot Settings > Web Login). Register your Allowed URLs and Redirect URL there. See OIDC Prerequisites. - Login Widget and Mini App flows are unaffected.
Full changelog: CHANGELOG.md
Full Changelog: v1.3.3...v1.4.0
v1.3.3
Fixed
bot_idactually ships this time (#11) — The v1.3.2 source had thebot_idfix but the npm dist was built before the change landed. The published package sentadditionalParams: { origin }instead ofadditionalParams: { origin, bot_id: botId }. This release rebuilds from the correct source. If you're on 1.3.2 and using OIDC, upgrade.
Added
- OIDC prerequisites documentation — Telegram's OIDC infrastructure is live (
oauth.telegram.org/.well-known/openid-configuration, JWKS, RS256 JWTs) but bot registration isn't publicly documented. Without it, the token endpoint returnsinvalid_clientand the auth endpoint falls back to Login Widget redirects (#tgAuthResulthash fragment instead of?code=authorization code). README now documents this:/setpublickeyvia @Botfather,/setdomain, and the fact that additional undocumented steps may be required. Troubleshooting section updated with OIDC-specific guidance.
Changed
- Test app restructured — Login Widget isolated to
/widgetpage, Mini App SDK loaded dynamically only on/miniapp, home page is now a hub with links. Prevents cross-flow interference during testing.
Full changelog: CHANGELOG.md
Full Changelog: v1.3.2...v1.3.3
v1.3.2
v1.3.1
v1.3.0
v1.2.0
What's New
Fixed
- Residual TS2532 errors in OIDC tests —
plugin.init!(mockCtx)could returnvoidbecause theinithook is conditionally spread. Added non-null assertions. Three fewer red squiggles.
Added
- Telegram test server support (
testModeoption) — settestMode: trueand your bot talks to Telegram's test environment DCs instead of production. HMAC verification is token-agnostic, so zero crypto changes needed. Logs a warning when combined with OIDC becauseoauth.telegram.orghas no documented test variant. BetterAuthPluginRegistrymodule augmentation — declares thetelegramplugin in Better Auth's plugin registry soctx.context.getPlugin("telegram")andctx.context.hasPlugin("telegram")are fully typed. Type-only, zero runtime impact.
Changed
GET /telegram/confignow returnstestModeboolean alongsidebotUsername,miniAppEnabled, andoidcEnabled.- Test count: 173 → 219 tests. 100% coverage across statements, branches, functions, and lines.
Migration from v1.1.0
No breaking changes. testMode is opt-in (default false). BetterAuthPluginRegistry module augmentation is type-only — zero runtime impact. Config endpoint now returns testMode boolean. Your existing code doesn't care.
Full Changelog: https://github.com/vcode-sh/better-auth-telegram/blob/main/CHANGELOG.md
Full Changelog: v1.1.0...v1.2.0
v1.1.0: Better Auth 1.5.0 Compatibility
Better Auth 1.5.0 Compatibility
The type mismatch era is over. #11 reported that better-auth-telegram exploded with type errors when used with better-auth@1.5.0. Turns out Better Auth 1.5 changed $ERROR_CODES from Record<string, string> to Record<string, RawError>. Fair enough.
What Changed
- Error codes migrated to
defineErrorCodes()—ERROR_CODESnow usesdefineErrorCodes()from@better-auth/core/utils/error-codes. Each error code is a properRawErrorobject ({ code, message }) instead of a plain string. - All
APIErrorthrows migrated toAPIError.from()— 14 throw sites updated fromthrow new APIError("STATUS", { message })tothrow APIError.from("STATUS", ERROR_CODES.X). Same behaviour, new API. - Removed
(ctx: any)on init hook — TypeScript now infersAuthContextfrom the plugin type instead of pretending everything isany. @better-auth/coreadded to tsup externals —defineErrorCodesimport resolved at runtime, not bundled.
Breaking Changes
- Peer dependency bumped to
better-auth@^1.5.0— if you're on 1.4.x, upgrade first. This is the minimum that satisfies the newBetterAuthPlugininterface.
Fixed
- Type mismatch with
better-auth@1.5.0(#11) — thanks to @flxxxxddd and @RainyPixel for reporting.
Verification
tsc --noEmit— 0 errorsvitest run— 173/173 tests passedtsupbuild — clean ESM + CJS + declarationsultracite check— 0 issues
Full Changelog: v1.0.0...v1.1.0
Full Changelog: v1.0.0...v1.1.0