Real World Example

Bank Maker-Checker Approvals

Banking back offices (ICICI, HDFC, Razorpay settlements) use a maker-checker rule: the person who creates a high-value payout cannot approve it. That is an authorization rule on data, not just a role.

src/payouts/payouts.service.ts

import { ForbiddenException, Injectable, NotFoundException } from '@nestjs/common';
import { PrismaService } from '../prisma/prisma.service';

@Injectable()
export class PayoutsService {
  constructor(private readonly prisma: PrismaService) {}

  async approve(payoutId: string, checker: { id: number; roles: string[] }) {
    if (!checker.roles.includes('checker')) throw new ForbiddenException('Only checkers can approve');
    const payout = await this.prisma.payout.findUnique({ where: { id: payoutId } });
    if (!payout) throw new NotFoundException();
    if (payout.createdById === checker.id) throw new ForbiddenException('Maker cannot approve own payout');
    if (payout.amountPaise > 10_00_000_00 && !checker.roles.includes('senior-checker')) {
      throw new ForbiddenException('Payouts above ₹10 lakh need a senior checker');
    }
    return this.prisma.payout.update({
      where: { id: payoutId, status: 'PENDING' },
      data: { status: 'APPROVED', approvedById: checker.id, approvedAt: new Date() },
    });
  }
}

Example

curl -i -X POST http://localhost:3000/payouts/po_81/approve -H "Authorization: Bearer <maker-token>"

Example output

HTTP/1.1 403 Forbidden
{"message":"Maker cannot approve own payout","error":"Forbidden","statusCode":403}