How I'm naming User-scoped APIs vs. System APIs

This may be a real beginner thing to be figuring out, but I’m working on both:

  • Good security practices
  • Phoenix module naming

Here’s my current idea.

# Customer-scoped APIs
IndexFlow.Domains.get!(customer_id, id)
IndexFlow.Sitemaps.list(customer_id)

# System APIs  
IndexFlow.Domains.Internal.get!(id)
IndexFlow.Sitemaps.Internal.bulk_update_status(ids, status)

I want this because the app is both end-user facing plus has batch jobs running on schedules. Those jobs need full access across all customers. But queries done on behalf of a customer need to be scoped to them. I want to make it obvious to me (and the default) when I’m more secure.

Now, as far as locating this code? I’ll probably create /domains/intrernal.ex, etc. I do dislike that this will be alongside my schema files, yet it’s a context. But my module files are getting way too big as it is…

Anyone else tackle this?

I use a different endpoint for admin purpose… mostly because of client request to have a clear separation with public facing endpoint.

But my core logic stays the same.

1 Like

I’m not saying this is a great solution for you, its just one I’ve used in an absurdly secure environment - in case it helps.

HTTP call → Service Layer → Broker Layer → Data Layer

  • Service layer checks that its a sane call (auth happened correctly, nothing fishy about the request) and passes it onto the Broker layer. It might format result for a particular purpose.
  • Broker layer checks that the caller is allowed to make that call, has proper access to see that data, etc, and executes queries/commands against the Data Layer.
  • Data Layer - think Repo calls.

Third-parties use the Service Layer, Processes use the Broker Layer.

I always pass the current Scope as the first argument to these functions (could also be the current User) and dispatch based on authorization rules.

1 Like