diff --git a/backend/src/routes/auth.js b/backend/src/routes/auth.js index af41420..86d28fd 100644 --- a/backend/src/routes/auth.js +++ b/backend/src/routes/auth.js @@ -28,16 +28,44 @@ const verifySchema = z.object({ }); /** - * Generate a SEP-10 authentication challenge. - * - * @route POST /auth/sep10 - * @param {string} public_key - The Stellar public key requesting a challenge - * @returns {Object} 200 - Challenge transaction and nonce - * @returns {string} 200.transaction - The unsigned SEP-10 challenge transaction - * @returns {string} 200.nonce - A unique nonce for this challenge (single-use) - * @returns {Object} 400 - Invalid public key format - * @returns {Object} 429 - Rate limit exceeded (max 10 per minute per IP) - * @throws {Error} 500 - Internal server error + * @swagger + * /auth/sep10: + * post: + * summary: Generate a SEP-10 authentication challenge + * tags: + * - Auth + * requestBody: + * required: true + * content: + * application/json: + * schema: + * type: object + * required: + * - public_key + * properties: + * public_key: + * type: string + * description: Stellar public key (starts with G) requesting a challenge + * responses: + * 200: + * description: Challenge generated successfully + * content: + * application/json: + * schema: + * type: object + * properties: + * transaction: + * type: string + * description: Unsigned SEP-10 challenge transaction (XDR) + * nonce: + * type: string + * description: Single-use nonce tied to this challenge + * 400: + * description: Invalid Stellar public key format + * 429: + * description: Rate limit exceeded (max 10 requests per IP per minute) + * 500: + * description: Internal server error */ router.post('/sep10', sep10Limiter, validate(sep10Schema), async (req, res) => { const { public_key } = req.body; @@ -51,22 +79,54 @@ router.post('/sep10', sep10Limiter, validate(sep10Schema), async (req, res) => { }); /** - * Verify a signed SEP-10 challenge and issue a JWT. - * - * The client must sign the challenge transaction returned from POST /auth/sep10 - * with their Stellar wallet and submit it here. Upon successful verification, - * a JWT is issued that can be used to authenticate subsequent API requests. - * - * @route POST /auth/verify - * @param {string} transaction - The signed SEP-10 challenge transaction - * @param {string} nonce - The nonce from the challenge (must match) - * @returns {Object} 200 - Authentication successful - * @returns {string} 200.token - JWT token (expires in 1 hour) - * @returns {string} 200.publicKey - The authenticated Stellar public key - * @returns {string} 200.role - User role: 'issuer' (admin) or 'patient' - * @returns {Object} 400 - Missing or invalid parameters - * @returns {Object} 401 - Invalid signature or nonce mismatch - * @throws {Error} 500 - Internal server error + * @swagger + * /auth/verify: + * post: + * summary: Verify a signed SEP-10 challenge and issue a JWT + * description: > + * The client signs the challenge transaction from POST /auth/sep10 with + * their Stellar wallet and submits it here. On success a short-lived JWT + * (1 hour) is returned scoped to the caller's role. + * tags: + * - Auth + * requestBody: + * required: true + * content: + * application/json: + * schema: + * type: object + * required: + * - transaction + * - nonce + * properties: + * transaction: + * type: string + * description: Signed SEP-10 challenge transaction (XDR) + * nonce: + * type: string + * description: Nonce returned by POST /auth/sep10 (must match) + * responses: + * 200: + * description: Authentication successful + * content: + * application/json: + * schema: + * type: object + * properties: + * token: + * type: string + * description: JWT (expires in 1 hour) + * wallet: + * type: string + * description: Authenticated Stellar public key + * role: + * type: string + * enum: [admin, patient] + * description: Role derived from the authenticated key + * 400: + * description: Missing or malformed parameters + * 401: + * description: Invalid signature or nonce mismatch */ router.post('/verify', validate(verifySchema), bruteForceGuard, (req, res) => { const { transaction, nonce } = req.body;