Suppose I want to implement multi-tenancy in a SaaS app by using a user-pool-per-tenant in my idp. I specify the tenant-id as a custom claim, then use the value of that claim to decide what data to serve to the user. The claim in the idp is immutable and I assign the value when the user is created.
For each api call, I validate the jwt according to best-practices, but how can I ensure that the value of the tenant-id claim is actually belonging to the intended tenant (pool). An example of a vulnerability I'm trying to protect against is a potential attacker creating a user in one pool with a tenant-id from another pool. Alternatively, the application code responsible for creating users in the pool assigns a wrong tenant-id value due to a bug.
An obvious solution is if the pool could assign the claim value based on a config of the pool itself, but as far as I can tell, my idp (AWS Cognito) doesn't have this ability. Another simple solution is to store a mapping in an external store (e.g. database/vault), but this exposes another potential attack vector and complicates system architecture to a degree I'd rather avoid. The user-pool-ids are unique, so I could use that as my tenant-id, but I don't like the idea of tying my tenant-id to the logic of the current idp of choice. Furthermore, pool-ids are (public) and I don't really want to expose my tenant ids outside of my system. Cognito user pools also have names which are immutable, but those aren't unique, so this is also not an option.
I've not been able to find much online on this topic, and it usually falls back to storing a mapping (pool-id -> tenant-id) externally to the pool. I'm implementing a microservice architecture and want each service to receive and validate the user's jwt. If I take the external mapping approach with this architecture, I'd have to create an authentication service and have each microservice call it for each request it receives. Caching could be added, but this would be a significant increase to system complexity.
As mentioned above, this could be easily solvable by the idp providing secure pool properties. Since it doesn't, I wonder if I'm missing something.