SuaveIO / suave

Suave is a simple web development F# library providing a lightweight web server and a set of combinators to manipulate route flow and task composition.
https://suave.io
Other
1.32k stars 198 forks source link

Support for a user object in the authenticate methods? #779

Open njlr opened 6 months ago

njlr commented 6 months ago

Usually when authenticating, we care about who is authenticated!

However, the current methods in Authentication support this only via context, which has some issues:

I propose a new combinator like this:

let authenticateBasicUserAsync (tryAuthenticate : string * string -> Async<'user option>) (makeProtectedPart : 'user -> WebPart) : WebPart =
  fun ctx ->
    async {
      let p = ctx.request
      match p.header "authorization" with
      | Choice1Of2 header ->
        let (typ, username, password) = parseAuthenticationToken header
        if (typ.Equals("basic")) then
          let! maybeUser = tryAuthenticate (username, password)

          match maybeUser with
          | Some user ->
            return! makeProtectedPart user (addUserName username ctx)
          | None ->
            return! challenge ctx
        else 
          return! challenge ctx
      | Choice2Of2 _ ->
        return! challenge ctx
    }

The existing combinators can be defined in terms of this:

let authenticateBasicAsync (f : string * string -> Async<bool>) (protectedPart : WebPart) : WebPart =
  authenticateBasicUserAsync 
    (fun (username, password) ->
      async {
        let! isAuthenticated = f (username, password)

        if isAuthenticated then
          return Some ()
        else
          return None 
      })
    (fun () -> protectedPart)