Files
zeekay 2fc1aa3bbe Take an IAM token as the only bearer, and call out as eSign's own IAM identity
A call without a session carries a Hanzo IAM access token: signed by a key in
hanzo.id's JWKS, issued by hanzo.id, minted for this app (aud = IAM_CLIENT_ID)
and unexpired. One resolver, getBearer, sits behind /v1/rpc, /v1/rest and the
download routes, and acts in the team X-Team-Id names: a person as the account
their sign-in linked, an application of IAM_ORG as the team's organisation
owner. API tokens no longer get into the API; Zapier, which could carry nothing
else, is deleted.

Outbound, one Machine mints eSign's client_credentials token for the service it
is spent at. notify uses it as before, and every webhook now carries one minted
for its endpoint's origin, so a Hanzo receiver verifies the caller against
hanzo.id instead of holding a shared secret.
2026-10-20 18:04:07 -07:00

32 lines
1.0 KiB
TypeScript

import { TsRestHttpError, fetchRequestHandler } from '@ts-rest/serverless/fetch';
import { Hono } from 'hono';
import { ApiContractV1 } from '@hanzo/esign-api/v1/contract';
import { ApiContractV1Implementation } from '@hanzo/esign-api/v1/implementation';
import { OpenAPIV1 } from '@hanzo/esign-api/v1/openapi';
// This is a bit nasty. Todo: Extract
import type { HonoEnv } from '@hanzo/esign-remix/server/router';
// This is bad, ts-router will be created on each request.
// But don't really have a choice here.
export const tsRestHonoApp = new Hono<HonoEnv>();
tsRestHonoApp
.get('/openapi', (c) => c.redirect('https://openapi-v1.esign.hanzo.ai'))
.get('/openapi.json', (c) => c.json(OpenAPIV1));
tsRestHonoApp.mount('/', async (request) => {
return fetchRequestHandler({
request,
contract: ApiContractV1,
router: ApiContractV1Implementation,
options: {
errorHandler: (err) => {
if (err instanceof TsRestHttpError && err.statusCode === 500) {
console.error(err);
}
},
},
});
});