Combine security and normal inputs in an endpoint

Hello there

Let’s say I have an endpoint like

endpoint
  .securityIn(auth.bearer[MyIdentityTokenClass])
  .in("toysProducers")
  .in(path[UUID]("toyProducerId")
  .out(jsonBody[Seq[Toy]])

The logic I need to apply to this endpoint is

  • Check that the token is valid: MyIdentityTokenClass => A
  • Check that the token is valid for my specific toy producer, i.e. it has read access for that specific resource: MyIdentityToken, UUID => B
  • The actual server logic: B => UUID => Seq[Toy] (B would be the response from the last security check)

The problem is, as far as I can tell, security and normal inputs are “segregated”.

I can think of two ways of solving the issue

  • Treating the toyProducerId as part of the security input, so that I would have an endpoint where securityInput = (MyIdentityTokenClass, UUID) and input = Unit

    • The security logic would then be (MyIdentityTokenClass, UUID) => Either[ErrorClass, UUID] and my server logic UUID => Unit => Seq[Toy]
  • Letting the securityInput only deal with the first check and return its own token, then apply the read permission logic in the server logic part

The first solution feels a bit dirty because it’s not clear from the endpoint’s definition that the toyProducerId is also used in the implementation logic.

The second one requires me to handle security logic in the implementation logic despite having a dedicated security logic already. Then again, one is authentication and the other is authorization, so it might make sense to treat them differently.

Is there a cleaner approach?
If not, which of the two I mentioned do you think is most appropriate?

Yes, you’re right that the security/normal inputs are segregated. One of the main use-cases for this features is to be able to define reusable endpoints, where the security logic is defined, but the server logic not yet.

So what might help you decide is if there’s multiple endpoints which use the toyProducerId for security and if so, if such a partially-applied endpoint definition might be reused.

But in general, not knowing the exact code-base, my first choice would be to go with the second option: performing a validity check in the security logic, and running further endpint-specific security in the server logic. Authentication/authz is also a good discriminator.