Repository navigation
feat: generate JWT and API key auth for TypeScript, Go and Python - #165
Merged
Merged
Conversation
auth0, clerk, cognito and api-key were accepted in .apsorc but generated no check: TypeScript returned no guard for them, Go wrote an unwired placeholder that accepted any bearer token, and Python wrote nothing. - New generic "jwt" provider for any issuer with a JWKS (Supabase Auth, Firebase, WorkOS, Okta, Better Auth's JWT plugin). audience is optional; Cognito checks client_id on access tokens. Only asymmetric algorithms. - TypeScript: jose-based JWT guard and a hashed API key guard. GuardsModule is now listed in autogen/index.ts; before this no generated guard (including better-auth and scopeBy) ever ran in a template project. GET /health stays public. - scopeBy: scoped controllers get @CrudAuth when auth is configured, so every query and write is limited to the caller's tenant; the scope guard fails closed when the caller has no tenant and compares ids as strings. - Go: golang-jwt + keyfunc middleware, or a hashed API key lookup, registered on the /api group. Enum fields now use the declared type name (they did not compile). - Python: a require_auth dependency on the generated router (PyJWT, or a hashed API key lookup). Enum types are created on DATABASE_SYNC, and related rows serialize as their columns instead of failing with a 500. - Go and Python refuse better-auth/custom-db-session instead of generating an open API. - generate adds jose / PyJWT[crypto] to the project. - scripts/auth-smoke.mjs + auth-smoke workflow: per language and provider, start the service on Postgres and check 401s for bad credentials, CRUD with good ones, and tenant isolation.
Better Auth's JWT plugin signs with EdDSA by default, and Clerk recommends rejecting tokens whose azp is not one of your origins. Both are covered in the auth smoke for all three languages.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
auth0,clerk,cognitoandapi-keywere accepted in.apsorcbut generated no token check. TypeScript returned no guard for them, Go wrote an unwired placeholder that accepted any bearer token, and Python wrote nothing. The docs presented all of them as working.While testing end to end, these turned up too:
autogen/index.tsnever listedGuardsModule, so no generated guard ran in a template project. That includesbetter-authand everyscopeByfilter.@apso/crudignores, and it compared numeric ids to string claims.DATABASE_SYNC, and creating a row with a relationship returned 500.greenletwas missing.What
jwtprovider for any issuer that publishes a JWKS. Auth0, Clerk and Cognito get claim defaults, and Cognito checksclient_idon access tokens. Only asymmetric algorithms are accepted.AUTH_JWT_ISSUER,AUTH_JWT_AUDIENCEandAUTH_JWKS_URIoverride the.apsorcvalues at runtime.ApiKey.keyHash, andstatusandexpiresAtare enforced when present.joseJWT guard and an API key guard;GuardsModulewired in;@CrudAuthon scoped controllers, so reads and writes stay in the caller's tenant;GET /healthstays public./apigroup.require_authdependency on the generated router.better-authandcustom-db-sessionwith a hint to usejwtvia Better Auth's JWT plugin.scopeByis enforced in TypeScript only, and Go and Python print a warning.Tests
test/lib/guards/auth-providers.test.ts: 37 unit tests. The full suite passes (514).scripts/auth-smoke.mjs, plus the newauth-smokeworkflow (PRs touching generators, weekly). For each language and each provider (auth0,clerk,cognito,jwt,api-key) it generates the service, starts it on Postgres, and checks:/healthis public;Locally (Postgres 16, Node 24, Go 1.25, Python 3.12), every check passes in all three languages.