Skip to content

Releases: vcode-sh/better-auth-telegram

v1.5.0

10 Mar 18:55

Choose a tag to compare

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

  • loginWidgetEnabled in 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

01 Mar 23:35

Choose a tag to compare

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_client resolved (#11) — The Client Secret is NOT the bot token. BotFather provides a separate secret via Bot Settings > Web Login. Removed non-standard origin and bot_id params from the auth URL. Clean standard OIDC now.
  • OIDC cross-domain redirect (#12) — origin was derived from the backend redirectURI, breaking setups where frontend and backend live on different domains. Telegram redirected to api.example.com/#tgAuthResult=... instead of redirect_uri?code=.... Removed origin entirely — Telegram uses the standard redirect_uri now.
  • Login Widget / Mini App P2002 crash (#13) — /telegram/signin and /telegram/miniapp/signin crashed with Unique constraint failed on email when the user already existed via OIDC. Now checks for existing users by telegramId before attempting creation. Links the account instead of creating a duplicate.

Added

  • oidc.clientSecret option — 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.clientSecret from 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

01 Mar 22:31

Choose a tag to compare

Fixed

  • bot_id actually ships this time (#11) — The v1.3.2 source had the bot_id fix but the npm dist was built before the change landed. The published package sent additionalParams: { origin } instead of additionalParams: { 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 returns invalid_client and the auth endpoint falls back to Login Widget redirects (#tgAuthResult hash fragment instead of ?code= authorization code). README now documents this: /setpublickey via @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 /widget page, 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

01 Mar 21:26

Choose a tag to compare

Full Changelog: v1.3.1...v1.3.2

v1.3.1

01 Mar 19:37

Choose a tag to compare

Full Changelog: v1.3.0...v1.3.1

v1.3.0

01 Mar 19:09

Choose a tag to compare

Full Changelog: v1.2.0...v1.3.0

v1.2.0

01 Mar 16:59

Choose a tag to compare

What's New

Fixed

  • Residual TS2532 errors in OIDC testsplugin.init!(mockCtx) could return void because the init hook is conditionally spread. Added non-null assertions. Three fewer red squiggles.

Added

  • Telegram test server support (testMode option) — set testMode: true and 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 because oauth.telegram.org has no documented test variant.
  • BetterAuthPluginRegistry module augmentation — declares the telegram plugin in Better Auth's plugin registry so ctx.context.getPlugin("telegram") and ctx.context.hasPlugin("telegram") are fully typed. Type-only, zero runtime impact.

Changed

  • GET /telegram/config now returns testMode boolean alongside botUsername, miniAppEnabled, and oidcEnabled.
  • 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

01 Mar 16:27

Choose a tag to compare

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_CODES now uses defineErrorCodes() from @better-auth/core/utils/error-codes. Each error code is a proper RawError object ({ code, message }) instead of a plain string.
  • All APIError throws migrated to APIError.from() — 14 throw sites updated from throw new APIError("STATUS", { message }) to throw APIError.from("STATUS", ERROR_CODES.X). Same behaviour, new API.
  • Removed (ctx: any) on init hook — TypeScript now infers AuthContext from the plugin type instead of pretending everything is any.
  • @better-auth/core added to tsup externalsdefineErrorCodes import 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 new BetterAuthPlugin interface.

Fixed

Verification

  • tsc --noEmit — 0 errors
  • vitest run — 173/173 tests passed
  • tsup build — clean ESM + CJS + declarations
  • ultracite check — 0 issues

Full Changelog: v1.0.0...v1.1.0

Full Changelog: v1.0.0...v1.1.0

v1.0.0: Telegram OIDC Support

01 Mar 14:03

Choose a tag to compare

🔐 Telegram OIDC (OpenID Connect) Support

Telegram finally joined the OAuth federation with Bot API 9.5, and we're here for it. Login Widget. Mini Apps. OIDC. The whole circus is now complete.

What's New

  • Telegram OIDC authentication — Standard OAuth 2.0 Authorization Code flow with PKCE via oauth.telegram.org. Proper grown-up auth instead of widget callbacks.
  • Phone number access — The phone scope gives you what the Login Widget never could. Set requestPhone: true and stop guessing.
  • RS256 JWT verification — ID tokens verified against Telegram's JWKS endpoint. Keys fetched and matched by kid — no hardcoded secrets, no trust-me-bro validation.
  • Zero custom endpoints — Injects a telegram-oidc provider into Better Auth's social login system via the init hook. Uses standard /sign-in/social and /callback/telegram-oidc routes.
  • New telegramPhoneNumber field — Added to the user schema, populated via OIDC phone scope.
  • 173 tests — 56 new OIDC tests. 100% coverage on oidc.ts. If it breaks, roast me on X.

Setup

// Server
telegram({
  botToken: process.env.TELEGRAM_BOT_TOKEN!,
  botUsername: "your_bot_username",
  oidc: {
    enabled: true,
    requestPhone: true,
  },
});

// Client
await authClient.signInWithTelegramOIDC({
  callbackURL: "/dashboard",
});

Breaking Changes

None. OIDC is opt-in (oidc.enabled: false by default). All existing Login Widget and Mini App flows are untouched.

New Configuration Options

Option Default Description
oidc.enabled false Enable Telegram OIDC flow
oidc.scopes ["openid", "profile"] OIDC scopes to request
oidc.requestPhone false Request phone number
oidc.requestBotAccess false Request bot access
oidc.mapOIDCProfileToUser Custom OIDC claims mapper

Database Migration

Add telegramPhoneNumber to your user table:

model User {
  // ... existing fields
  telegramPhoneNumber String?
}

Links

Full Changelog: v0.4.0...v1.0.0

What's Changed

  • chore(deps-dev): bump happy-dom from 20.6.3 to 20.7.0 by @dependabot[bot] in #5
  • chore(deps): bump actions/checkout from 4 to 6 by @dependabot[bot] in #7
  • chore(deps-dev): bump better-auth from 1.4.18 to 1.4.19 in the dev-dependencies group by @dependabot[bot] in #8

New Contributors

Full Changelog: v0.4.0...v1.0.0

v0.4.0

21 Feb 13:08

Choose a tag to compare

Full Changelog: v0.3.2...v0.4.0