Bearer Token Authenticator
The bearer token authenticator uses TSecTokenSettings
for configuration:
final case class TSecTokenSettings(
expirationTime: FiniteDuration,
maxIdle: Option[FiniteDuration]
)
And for token storage, it uses TSecBearerToken
for storage:
final case class TSecBearerToken[I](
id: SecureRandomId, //Your secure random Id
identity: I, //Your user ID type. in the case of our example, User has id type Int.
expiry: Instant, //The absolute expiration time
lastTouched: Option[Instant] //Possible rolling window expiration
) extends Authenticator[I]
This authenticator uses a SecureRandomId
(A 32-bit Id generated with a secure random number generator) as a bearer
token to authenticate with information held server-side.
Notes:
- Not vulnerable to CSRF.
- Okay to use with
CORS
- Requires synchronized backing store.
Authenticator creation
import cats.effect.IO
import org.http4s.HttpService
import org.http4s.dsl.io._
import tsec.authentication._
import tsec.common.SecureRandomId
import concurrent.duration._
object BearerTokenExample {
import http4sExamples.ExampleAuthHelpers._
val bearerTokenStore =
dummyBackingStore[IO, SecureRandomId, TSecBearerToken[Int]](s => SecureRandomId.coerce(s.id))
//We create a way to store our users. You can attach this to say, your doobie accessor
val userStore: BackingStore[IO, Int, User] = dummyBackingStore[IO, Int, User](_.id)
val settings: TSecTokenSettings = TSecTokenSettings(
expiryDuration = 10.minutes, //Absolute expiration time
maxIdle = None
)
val bearerTokenAuth =
BearerTokenAuthenticator(
bearerTokenStore,
userStore,
settings
)
val Auth =
SecuredRequestHandler(bearerTokenAuth)
val authservice: TSecAuthService[TSecBearerToken[Int], User, IO] = TSecAuthService {
case GET -> Root asAuthed user =>
Ok()
}
/*
Now from here, if want want to create services, we simply use the following
(Note: Since the type of the service is HttpService[IO], we can mount it like any other endpoint!):
*/
val service: HttpService[IO] = Auth.liftService(TSecAuthService {
//Where user is the case class User above
case request@GET -> Root / "api" asAuthed user =>
/*
Note: The request is of type: SecuredRequest, which carries:
1. The request
2. The Authenticator (i.e token)
3. The identity (i.e in this case, User)
*/
val r: SecuredRequest[IO, User, TSecBearerToken[Int]] = request
Ok()
})
}