package io.github.pauljamescleary.petstore.domain.authentication import cats.MonadError import cats.effect._ import io.github.pauljamescleary.petstore.domain.users.{Role, User} import org.http4s.Response import tsec.authentication.{ AugmentedJWT, BackingStore, IdentityStore, JWTAuthenticator, SecuredRequest, TSecAuthService, } import tsec.authorization.BasicRBAC import tsec.common.SecureRandomId import tsec.jws.mac.JWSMacCV import tsec.jwt.algorithms.JWTMacAlgo import tsec.mac.jca.MacSigningKey import scala.concurrent.duration._ object Auth { def jwtAuthenticator[F[_]: Sync, Auth: JWTMacAlgo]( key: MacSigningKey[Auth], authRepo: BackingStore[F, SecureRandomId, AugmentedJWT[Auth, Long]], userRepo: IdentityStore[F, Long, User], )(implicit cv: JWSMacCV[F, Auth]): JWTAuthenticator[F, Long, User, Auth] = JWTAuthenticator.backed.inBearerToken( expiryDuration = 1.hour, maxIdle = None, tokenStore = authRepo, identityStore = userRepo, signingKey = key, ) private def _allRoles[F[_], Auth]( implicit F: MonadError[F, Throwable], ): BasicRBAC[F, Role, User, Auth] = BasicRBAC.all[F, Role, User, Auth] def allRoles[F[_], Auth]( pf: PartialFunction[SecuredRequest[F, User, AugmentedJWT[Auth, Long]], F[Response[F]]], )(implicit F: MonadError[F, Throwable]): TSecAuthService[User, AugmentedJWT[Auth, Long], F] = TSecAuthService.withAuthorization(_allRoles[F, AugmentedJWT[Auth, Long]])(pf) def allRolesHandler[F[_], Auth]( pf: PartialFunction[SecuredRequest[F, User, AugmentedJWT[Auth, Long]], F[Response[F]]], )( onNotAuthorized: TSecAuthService[User, AugmentedJWT[Auth, Long], F], )(implicit F: MonadError[F, Throwable]): TSecAuthService[User, AugmentedJWT[Auth, Long], F] = TSecAuthService.withAuthorizationHandler(_allRoles[F, AugmentedJWT[Auth, Long]])( pf, onNotAuthorized.run, ) private def _adminOnly[F[_], Auth]( implicit F: MonadError[F, Throwable], ): BasicRBAC[F, Role, User, Auth] = BasicRBAC[F, Role, User, Auth](Role.Admin) def adminOnly[F[_], Auth]( pf: PartialFunction[SecuredRequest[F, User, AugmentedJWT[Auth, Long]], F[Response[F]]], )(implicit F: MonadError[F, Throwable]): TSecAuthService[User, AugmentedJWT[Auth, Long], F] = TSecAuthService.withAuthorization(_adminOnly[F, AugmentedJWT[Auth, Long]])(pf) }