SmartSpend – Agentic Expense Management with Auth0 FGA
This is a submission for the Auth0 for AI Agents Challenge
What I Built
I built SmartSpend, an intelligent expense management system designed to solve the complex authorization challenges in a typical organization.
The core problem with expense management isn’t just tracking receipts; it’s managing who can see, approve, and audit what. Traditional systems often have this logic hard-coded, making it brittle and difficult to manage.
SmartSpend solves this by combining a conversational AI agent with a powerful, fine-grained authorization model. For this demo, the application supports a multi-layered organizational structure with several key personas:
- Dina, a Software Engineer who submits expenses.
- Raj, a Manager who approves expenses for his direct reports.
- Chen, a VP who can approve expenses for his direct reports and their direct reports.
- Frank, a Finance Auditor who has read-only “overseer” access to all expenses.
Users can log in using Auth0 for GenAI, file new expenses, and chat with an AI assistant to get a status on their submissions. Managers can instruct the same AI agent to approve or deny expenses, with every action being checked against a central authorization model using Auth0 FGA.
Demo
Here is a link to the project repository and a video of the solution in action.
Project Link: https://fga-spend-guard-3.vercel.app/
You can use the Demo Mode to play around without authentication, or Sign In with the following test credentials:
Dina Dev
dina.dev@company.com
123@okta
Raj Manager
raj.manager@company.com
123@okta
Chen VP
chen.vp@company.com
123@okta
Frank Finance
frank.finance@company.com
123@okta
Demo Video: https://www.youtube.com/watch?v=bBi7ueX0Sg8
How it Works
- Authentication: The user (e.g., Dina) signs in using the Auth0 Universal Login page.
- Submitting an Expense: Dina submits a new expense for “Hackathon Food.” In the background, this not only adds the expense to the database but also creates new relationship tuples in the Auth0 FGA model, defining Dina as the owner of this new expense.
-
Manager’s View: Dina’s manager, Raj, logs in. He sees his own expenses and all pending expenses from his direct reports that require his approval.
-
AI Agent as an Actor: Raj instructs the AI agent: “Approve expense 112” (Dina’s food expense).
-
FGA Check (Success): The agent’s backend first makes an authorization check with Auth0 FGA to see if user:raj has the approver relation for expense:112. Since he is Dina’s manager, FGA returns true. The agent then proceeds to get the necessary tokens and make the API call to approve the expense.
-
FGA Check (Failure): We also test the failure case. Raj instructs the agent: “Approve 103” (an expense he submitted himself). The agent checks Auth0 FGA, which knows a user cannot approve their own expense. It correctly returns false, and the agent informs Raj, “You do not have permission to approve this expense.”
- Auditor View: Finally, the auditor (Frank) can log in and view all expenses in the system, but the FGA model prevents him from having any approval permissions.
How I Used Auth0 for AI Agents
Auth0 was the foundation of this project, handling both authentication (the “who”) and authorization (the “what”).
1. User Authentication (Auth0 Universal Login)
I used Auth0 Universal Login to secure the application and handle all user sign-ins. This provides a secure, battle-tested authentication flow out of the box. The user’s authenticated email is then used as the user_id in the Auth0 FGA model, which is the crucial link between the user’s identity and their permissions.
2. Agent Authorization (Auth0 FGA)
This is the core of the project. I used Auth0 FGA to completely externalize all authorization logic from the application.
I designed an FGA schema that models the complex relationships of an expense system:
type user: Can have a manager (who is also a user).
type department: Can have member (a user) and a finance_auditor (a user).
type expense: Has relations for:
- owner: The user who submitted it.
- department: The department the owner belongs to.
- approver: Can be the owner’s direct manager or that manager’s manager (for multi-level approvals).
- finance_auditor: The finance_auditor from the expense’s department.
The AI agent is not just a chatbot; it’s an actor that must obey these FGA rules. When a user (like Raj) gives the agent a command, the backend logic performs these steps:
-
Parse Intent: The AI agent (using an OpenAI model) understands the user wants to “approve” expense:112.
-
Check Authorization: Before taking any action, the system asks Auth0 FGA a simple question: “Can user:raj perform the approve action on expense:112?”
-
Act on Permission:
- If FGA returns true, the agent proceeds, retrieves the necessary access tokens, and makes the API call to update the expense.
- If FGA returns false, the agent stops and informs the user they don’t have permission.
This critical step ensures the AI agent cannot be tricked or misused. It’s bound by the exact same fine-grained rules as a human clicking a button in the UI.
Lessons Learned and Takeaways
- FGA is a superpower for complex business logic. Modeling multi-level approvals (manager’s manager) and special observer roles (the auditor) would be a nightmare to hard-code and maintain. With Auth0 FGA, this logic is declarative, easy to understand, and can be changed without redeploying the app.
- An AI agent must be an authorized actor. The biggest takeaway was that an AI agent is a powerful tool, which also makes it a potential security risk. It’s not enough to just authenticate the user. The actions the agent takes on the user’s behalf must also be authorized. Coupling the agent’s intent (from the LLM) with an FGA check (from Auth0) is the key to building secure AI agents.
- Real-time tuples are essential. A key part of the flow was creating the new FGA relationship tuples (e.g., dina is owner of expense:112) at the exact moment the expense is created. This keeps the authorization model perfectly in sync with the application’s data.
- The Auth0 stack is a perfect fit. Using Auth0 Universal Login for authentication and Auth0 FGA for authorization felt like a very clean and powerful separation of concerns, letting me focus on the business logic instead of building security primitives.





