Introduction

Say we have an endpoint that must perform an action only if one has elevated permissions (i.e. delete some entity).
  1. let delete (id: string) =
  2. fun (next: HttpFunc) (httpContext : HttpContext) ->
  3. let result =
  4. AuthApi.authorize httpContext
  5. |> Result.bind (fun _ -> ElasticAdapter.deleteRoute id)
  6. match result with
  7. | Ok _ -> text "" next httpContext
  8. | Error "ItemNotFound" -> RequestErrors.BAD_REQUEST "" next httpContext
  9. | Error "Forbidden" -> RequestErrors.FORBIDDEN "" next httpContext
  10. | Error _ -> ServerErrors.INTERNAL_ERROR "" next httpContext
Note that in a discriminated union we match multiple error cases, and one of them is a Forbidden case
Now let's have a look at the code of the authorize method inside AuthApi
  1. let authorize (httpContext : HttpContext) =
  2. let authorizationHeader = httpContext.GetRequestHeader "Authorization"
  3. let authorizationResult =
  4. authorizationHeader
  5. |> Result.bind JwtValidator.validateToken
  6. authorizationResult
And here's the JtwValidator
  1. module JwtValidator
  2. open Microsoft.IdentityModel.Tokens
  3. open System.Text
  4. open System.IdentityModel.Tokens.Jwt
  5. open System
  6. let key = "<your key>"
  7. let createValidationParameters =
  8. let validationParameters = TokenValidationParameters()
  9. validationParameters.ValidateAudience <- false
  10. validationParameters.ValidateLifetime <- true
  11. validationParameters.ValidateIssuer <- false
  12. validationParameters.IssuerSigningKey <- SymmetricSecurityKey(Encoding.UTF8.GetBytes(key))
  13. validationParameters
  14. let validateToken (token: string) =
  15. try
  16. let tokenHandler = JwtSecurityTokenHandler()
  17. let validationParameters = createValidationParameters
  18. let mutable resToken : SecurityToken = null
  19. tokenHandler.ValidateToken(token, validationParameters, &resToken)
  20. |> ignore
  21. Result.Ok()
  22. with
  23. | _ -> Result.Error "Forbidden"