Hi @jpoland00, thanks for the detailed write-up. We’ve received your issue report with the patch and verification notes, so you don’t need to send anything else for now.
Short answer: the admission logic doesn’t need a generator change. The durable place for app-specific sign-in rules is lib/auth.ts, which your app already owns.
Which auth files Teable owns
- Rewritten on every sync, so edits won’t survive:
app/auth/*/callback/route.ts, lib/public-url.ts, lib/credentials.ts, lib/request.ts
- Generated once when login is first enabled, then yours (sync never overwrites them):
lib/auth.ts, app/login/page.tsx, app/login/actions.ts, proxy.ts, components/auth/user-menu.tsx
What Teable checks before a session exists
The access mode in Login settings is enforced on Teable’s server before any session token is issued, for every provider. With “Existing users only”, an email that isn’t in the user table is turned away there: no email code is sent, and an OAuth sign-in comes back as an error instead of a code, so there’s nothing for your callback to exchange. The check runs again on every getSession() / requireAuth(), so deleting a user’s row or changing its email ends their session at the next check.
Where rules beyond that go (active flag, duplicate emails, your own login history)
The callback routes are deliberately thin. They call exchangeOAuthCode() from lib/auth.ts, and if it returns { success: false } they redirect to /login without setting a cookie. Every path that sets the session cookie runs through lib/auth.ts:
- direct OAuth callback:
exchangeOAuthCode()
- popup sign-in (relay in
app/login/actions.ts): setSessionFromToken()
- email code:
verifyCode()
Put your admission check and login-history write in those functions, before cookieStore.set(...). When you deny, return a generic error string: the callback copies it into the message query parameter.
Put the same check in getSession() too. A sign-in check doesn’t end a session that was already issued (sessions last up to 7 days), and proxy.ts only checks the cookie’s signature and expiry. Calling requireAuth() from a shared server layout makes every page render re-validate, not just your data actions.
The App Builder agent’s guide tells it not to touch auth files unless asked, so ask it explicitly to edit lib/auth.ts.
The TypeScript errors
Those are ours. All three reproduce with the scaffold’s own settings (TypeScript 5.9.3, strict: false):
- the callbacks read
result.error after checking !result.success, which doesn’t narrow the union when strictNullChecks is off
lib/credentials.ts passes a { message?: string } body to serverCodeOf (TS2559)
They don’t affect runtime behavior, and app builds skip type checking. We’ll still fix them in the templates. Those files are platform-managed, so the fix reaches your app on its next sync with nothing for you to do. We’ll reply here when it’s live.