init studio auth backend

This commit is contained in:
2026-07-01 17:36:34 +09:00
commit 87f6f46d3c
35 changed files with 2492 additions and 0 deletions
+171
View File
@@ -0,0 +1,171 @@
# ATNMY STDO Auth
Central JWT auth server for Autonomy Studio and launched apps.
## Stack
- Bun
- Hono
- PostgreSQL
- Redis
- Prisma
- JWT access tokens
- Opaque refresh tokens stored in Redis
- One-time handoff tokens for app SSO stored in Redis
## Local Run
```bash
cp .env.example .env
docker compose up -d postgres redis
bun install
bun run db:generate
bun run db:migrate
bun run db:seed
bun run dev
```
Default server:
```text
http://localhost:4100
```
Default backing services:
```text
PostgreSQL: localhost:5434
Redis: localhost:6380
```
Default seeded admin:
```text
admin@futuredrive.net / admin1234
```
Change this before using the service outside local development.
## API
### Login
```http
POST /auth/login
Content-Type: application/json
{
"email": "admin@futuredrive.net",
"password": "admin1234"
}
```
Returns:
```json
{
"accessToken": "...",
"accessTokenExpiresIn": 900,
"refreshToken": "...",
"refreshTokenExpiresIn": 2592000,
"user": {
"id": "...",
"email": "admin@futuredrive.net",
"name": "ATNMY Studio Admin",
"role": "ADMIN",
"roles": ["ADMIN"]
}
}
```
### Current User
```http
GET /auth/me
Authorization: Bearer <accessToken>
```
### Refresh
```http
POST /auth/refresh
Content-Type: application/json
{
"refreshToken": "<refreshToken>"
}
```
Refresh tokens are rotated on every use.
### Logout
```http
POST /auth/logout
Content-Type: application/json
{
"refreshToken": "<refreshToken>"
}
```
### Create App Handoff Token
Launcher calls this before launching ADS IDE or another app.
```http
POST /auth/handoff
Authorization: Bearer <launcherAccessToken>
Content-Type: application/json
{
"audienceApp": "ADS IDE"
}
```
Returns a short-lived one-time token:
```json
{
"handoffToken": "...",
"expiresIn": 60,
"audienceApp": "ADS IDE"
}
```
### Exchange App Handoff Token
The launched app calls this on startup.
```http
POST /auth/handoff/exchange
Content-Type: application/json
{
"handoffToken": "...",
"audienceApp": "ADS IDE"
}
```
Returns the launched app's own access/refresh token pair.
## Launcher Integration Sketch
```ts
const handoff = await fetch(`${AUTH_URL}/auth/handoff`, {
method: 'POST',
headers: {
authorization: `Bearer ${accessToken}`,
'content-type': 'application/json'
},
body: JSON.stringify({ audienceApp: 'ADS IDE' })
}).then((r) => r.json())
spawn(execBin, [
`--url=${encodeURIComponent(url)}`,
`--handoff-token=${encodeURIComponent(handoff.handoffToken)}`,
`--auth-url=${encodeURIComponent(AUTH_URL)}`
])
```
ADS IDE then calls `/auth/handoff/exchange` and stores the returned session.