Introduction
Say we have an endpoint that must perform an action only if one has elevated permissions (i.e. delete some entity).
- let delete (id: string) =
- fun (next: HttpFunc) (httpContext : HttpContext) ->
- let result =
- AuthApi.authorize httpContext
- |> Result.bind (fun _ -> ElasticAdapter.deleteRoute id)
- match result with
- | Ok _ -> text "" next httpContext
- | Error "ItemNotFound" -> RequestErrors.BAD_REQUEST "" next httpContext
- | Error "Forbidden" -> RequestErrors.FORBIDDEN "" next httpContext
- | 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
- let authorize (httpContext : HttpContext) =
- let authorizationHeader = httpContext.GetRequestHeader "Authorization"
- let authorizationResult =
- authorizationHeader
- |> Result.bind JwtValidator.validateToken
- authorizationResult
And here's the JtwValidator
- module JwtValidator
-
- open Microsoft.IdentityModel.Tokens
- open System.Text
- open System.IdentityModel.Tokens.Jwt
- open System
-
- let key = "<your key>"
-
- let createValidationParameters =
- let validationParameters = TokenValidationParameters()
- validationParameters.ValidateAudience <- false
- validationParameters.ValidateLifetime <- true
- validationParameters.ValidateIssuer <- false
- validationParameters.IssuerSigningKey <- SymmetricSecurityKey(Encoding.UTF8.GetBytes(key))
- validationParameters
-
- let validateToken (token: string) =
- try
- let tokenHandler = JwtSecurityTokenHandler()
- let validationParameters = createValidationParameters
- let mutable resToken : SecurityToken = null
- tokenHandler.ValidateToken(token, validationParameters, &resToken)
- |> ignore
- Result.Ok()
- with
- | _ -> Result.Error "Forbidden"