feat(api): include role in /api/me + allow admin origin in CORS

Add `role: Role` to the shared `PublicUser` contract and return it from
`GET /api/me` (defaulting to 'worker' when the session user has no role).
This lets the planned admin app gate access by role.

Also add the admin dev origin `http://localhost:5174` to the default
`WEB_ORIGINS` (env.ts) and to `.env.example`, so the admin SPA on :5174 can
reach the API at :3000 cross-origin (drives both hono/cors and better-auth
trustedOrigins).
This commit is contained in:
Bas van Rossem
2026-06-17 18:53:39 +02:00
parent bb0a0b2a57
commit 02b7522b87
6 changed files with 50 additions and 8 deletions

View File

@@ -2,6 +2,7 @@ import { describe, it, expect } from 'vitest';
import { createApp } from '../src/app';
const ORIGIN = 'http://localhost:5173';
const ADMIN_ORIGIN = 'http://localhost:5174';
describe('cors', () => {
it('answers a CORS preflight for the SPA origin', async () => {
@@ -18,6 +19,20 @@ describe('cors', () => {
expect(allowMethods).toContain('GET');
});
it('answers a CORS preflight for the admin SPA origin', async () => {
const app = createApp();
const res = await app.request('/api/activities', {
method: 'OPTIONS',
headers: {
Origin: ADMIN_ORIGIN,
'Access-Control-Request-Method': 'GET',
},
});
expect(res.headers.get('access-control-allow-origin')).toBe(ADMIN_ORIGIN);
const allowMethods = res.headers.get('access-control-allow-methods') ?? '';
expect(allowMethods).toContain('GET');
});
it('exposes set-auth-token to the SPA origin', async () => {
const app = createApp();
const res = await app.request('/api/activities', {

View File

@@ -19,4 +19,24 @@ describe('GET /api/me', () => {
const body = await res.json();
expect(body.user.email).toBe(email);
});
it('returns role "worker" for a worker token', async () => {
const app = createApp();
const token = await authToken(app, 'worker-role@example.com', 'worker');
const res = await app.request('/api/me', { headers: bearer(token) });
expect(res.status).toBe(200);
const body = await res.json();
expect(body.user.role).toBe('worker');
});
it('returns role "admin" for an admin token', async () => {
const app = createApp();
const token = await authToken(app, 'admin-role@example.com', 'admin');
const res = await app.request('/api/me', { headers: bearer(token) });
expect(res.status).toBe(200);
const body = await res.json();
expect(body.user.role).toBe('admin');
});
});