HttpFs.Auth0


HttpFs.Auth0

HttpFs.Auth0 provides constructs which make it easier to use Auth0 when interacting with protected APIs.

This library focuses on server-to-server interactions, where one service needs to authenticate itself to another service in order to gain access to a provided resource. This library also includes a TokenCache for transiently caching ID tokens while they remain valid.

HttpFs.Auth0 also supports a knock-first workflow, where an attempt is made to interact with a resource first. In this case, if the resource sends back a 401 Unauthorized response, then the request can be retried after (possibly generating and) adding the Auth0 token to the request.

The HttpFs.Auth0 library can be installed from NuGet:
PM> Install-Package HttpFs.Auth0

Example

The following shows a simple flow for authenticating with an API. It uses the Auth0 demo app credentials from their SSO Heroku application. You can get your own Auth0 account to test with by going to https://www.auth0.com.

 1: 
 2: 
 3: 
 4: 
 5: 
 6: 
 7: 
 8: 
 9: 
10: 
11: 
12: 
13: 
14: 
15: 
16: 
17: 
18: 
19: 
20: 
21: 
22: 
open Hopac
open HttpFs.Client
open HttpFs.Auth0

let cp =
  { AuthenticationHost = "fabrikam.auth0.com"
    ClientId = ClientId.create "ZDC7qh6mcXaQT6ilyiTWPmmfFI7L0aTs" }

let ac =
  UsernamePassword ("FabrikamAD","publicdemo","TestUser123")

let atJ =
  Authentication.createRequest cp ac
  |> Authentication.tryAuthenticate
  |> Alt.afterFun Authentication.AuthenticationResult.toChoice

let at = run atJ |> Choice.getOrFail

let respJ =
  Request.createUrl Get "http://www.example.com/protectedResource"
  |> Auth0Client.addAuth0TokenHeader at
  |> getResponse

The next example demonstrates how to set up a token cache and validate the client parameters returned by the protected resource against a whitelist of known client parameters. This helps to ensure that a malicious resource can't trick you into sending your credentials to a malicious authentication server.

The token cache helps to reduce the load on the Authentication API, keeping the token in memory while the token remains valid.

 1: 
 2: 
 3: 
 4: 
 5: 
 6: 
 7: 
 8: 
 9: 
10: 
11: 
12: 
13: 
14: 
15: 
16: 
17: 
18: 
19: 
20: 
21: 
22: 
23: 
24: 
25: 
26: 
27: 
28: 
let cep = CacheExpirationParameters.create' 300L 10L 60L
let tc = run <| TokenCache.create ()

let credentialMap = Map.ofList [ cp, ac ]
let prefixWhitelist = [ Uri "https://www.example.com/", cp ]

let tryGetCredentialsJob (uri : Uri) cp =
  let isWhitelisted (uri : Uri) (whitelistedUri : Uri, validParams : ClientParams) =
    if whitelistedUri.IsBaseOf uri && cp = validParams then Some cp else None
  prefixWhitelist
  |> List.tryPick (isWhitelisted uri)
  |> Option.bind (fun cp -> Map.tryFind cp credentialMap)
  |> Job.result

let tryAuthenticateClient uri cp =
  Authentication.tryAuthenticateFromSource tryGetCredentialsJob uri cp

let tryGetAuthToken uri =
  TokenCache.tryGetTokenWithFill cep (tryAuthenticateClient uri) tc

let respCToStringJ = function
  | Choice1Of2 resp -> Response.readBodyAsString resp
  | Choice2Of2 ex -> Job.result <| "Failed: " + string ex

let respStrA =
  Request.createUrl Get "http://www.example.com/protectedResource"
  |> Auth0Client.tryGetResponseWithRetryOnAuthRequired tryGetAuthToken
  |> Alt.afterJob respCToStringJ

Logging

This library uses the logging façade provided by Http.Fs under then HttpFs.Logging namespace. You can enable logging by initializing the façade and hooking it to your logging framework of choice.

Setting up logging:

1: 
2: 
3: 
4: 
5: 
6: 
open HttpFs.Logging

Global.initialise
  { Global.DefaultConfig with
      getLogger = fun _ -> ConsoleWindowTarget(Verbose) :> Logger
  }

Example logs:

[D] 2016-08-31T16:26:22.9841451+00:00: 152707349 µs [HttpFs.Auth0.Authentication.tryAuthenticate.responseTime]
[D] 2016-08-31T16:26:22.9841451+00:00: 152707349 µs [HttpFs.Auth0.Authentication.tryAuthenticate.responseTime.fabrikam_auth0_com]
[D] 2016-08-31T16:26:22.9841451+00:00: 152707349 µs [HttpFs.Auth0.Authentication.tryAuthenticate.responseTime.fabrikam_auth0_com./oauth/ro]
[D] 2016-08-31T16:26:23.0011451+00:00: Received response from authentication API https://fabrikam.auth0.com/oauth/ro with status code 200 [HttpFs.Auth0.Authentication]
[V] 2016-08-31T16:26:23.0101451+00:00: Reading authentication response [HttpFs.Auth0.Authentication]
[V] 2016-08-31T16:26:23.0191451+00:00: Read authentication response [HttpFs.Auth0.Authentication]
 - length: 380
[V] 2016-08-31T16:26:23.1051451+00:00: Successfully decoded authentication response [HttpFs.Auth0.Authentication]

Note that you may see the following warning from Hopac. We are working to make this warning go away in a future version, but you should experience no adverse effects as the run utilized by Logary returns very quickly.

 1: 
 2: 
 3: 
 4: 
 5: 
 6: 
 7: 
 8: 
 9: 
10: 
11: 
12: 
13: 
14: 
15: 
16: 
17: 
18: 
19: 
20: 
21: 
WARNING: You are making a blocking call from within a Hopac worker thread, which means that your program may deadlock.
First occurrence (there may be others):
  at System.Environment.GetStackTrace(Exception e, Boolean needFileInfo)
  at System.Environment.get_StackTrace()
  at Hopac.Core.Condition.Wait(Object o, Int32& v)
  at Hopac.Scheduler.run[x](Scheduler sr, Job`1 xJ)
  at Logary.Adapters.Facade.LogaryFacadeAdapter.values@188.Invoke(Object x)
  at <StartupCode$FSharp-Core>Reflect.Invoke@961-4.Invoke(T1 inp)
  at HttpFs.Logging.Global.f@1-1(Flyweight this, Unit _arg1)
  at HttpFs.Logging.Global.Flyweight.withLogger[a](FSharpFunc`2 action)
  at HttpFs.Auth0.Auth0Client.u2xJ@1-3[a](FSharpFunc`2 u2cp2atOJ, Uri uri, ClientParams cp, Unit unitVar)
  at HttpFs.Auth0.Auth0Client.tryGetAuth0TokenWithLogging@526-39.Do()
  at Hopac.Core.JobDelay`1.DoJob(Worker& wr, Cont`1 xK)
  at Hopac.Core.Always`1.DoJob(Worker& wr, Cont`1 xK)
  at Hopac.Promise`1.Fulfill.Do(Worker& wr, T t)
  at Hopac.Promise`1.Fulfill.DoWork(Worker& wr)
  at Hopac.Core.Worker.Run(Scheduler sr, Int32 me)
  at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
  at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
  at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
  at System.Threading.ThreadHelper.ThreadStart()

Samples & documentation

The API reference is automatically generated from Markdown comments in the library implementation.

  • API Reference contains automatically generated documentation for all types, modules and functions in the library. This includes additional brief samples on using most of the functions.

Contributing and copyright

The project is hosted on GitHub where you can report issues, fork the project and submit pull requests. If you're adding a new public API, please also consider adding samples that can be turned into a documentation. You might also want to read the library design notes to understand how it works.

The library is available under Apache 2.0 license, which allows modification and redistribution for both commercial and non-commercial purposes. For more information see the License file in the GitHub repository.

namespace System
namespace Hopac
module Hopac

from Hopac
val run : Hopac.Job<'x> -> 'x

Full name: Hopac.Hopac.run
Multiple items
module Job

from Hopac

--------------------
type Job<'T> =

Full name: Hopac.Job<_>
val unit : unit -> Hopac.Job<unit>

Full name: Hopac.Job.unit
Multiple items
module Choice

from YoLo

--------------------
type Choice<'T1,'T2> =
  | Choice1Of2 of 'T1
  | Choice2Of2 of 'T2

Full name: Microsoft.FSharp.Core.Choice<_,_>

--------------------
type Choice<'T1,'T2,'T3> =
  | Choice1Of3 of 'T1
  | Choice2Of3 of 'T2
  | Choice3Of3 of 'T3

Full name: Microsoft.FSharp.Core.Choice<_,_,_>

--------------------
type Choice<'T1,'T2,'T3,'T4> =
  | Choice1Of4 of 'T1
  | Choice2Of4 of 'T2
  | Choice3Of4 of 'T3
  | Choice4Of4 of 'T4

Full name: Microsoft.FSharp.Core.Choice<_,_,_,_>

--------------------
type Choice<'T1,'T2,'T3,'T4,'T5> =
  | Choice1Of5 of 'T1
  | Choice2Of5 of 'T2
  | Choice3Of5 of 'T3
  | Choice4Of5 of 'T4
  | Choice5Of5 of 'T5

Full name: Microsoft.FSharp.Core.Choice<_,_,_,_,_>

--------------------
type Choice<'T1,'T2,'T3,'T4,'T5,'T6> =
  | Choice1Of6 of 'T1
  | Choice2Of6 of 'T2
  | Choice3Of6 of 'T3
  | Choice4Of6 of 'T4
  | Choice5Of6 of 'T5
  | Choice6Of6 of 'T6

Full name: Microsoft.FSharp.Core.Choice<_,_,_,_,_,_>

--------------------
type Choice<'T1,'T2,'T3,'T4,'T5,'T6,'T7> =
  | Choice1Of7 of 'T1
  | Choice2Of7 of 'T2
  | Choice3Of7 of 'T3
  | Choice4Of7 of 'T4
  | Choice5Of7 of 'T5
  | Choice6Of7 of 'T6
  | Choice7Of7 of 'T7

Full name: Microsoft.FSharp.Core.Choice<_,_,_,_,_,_,_>
val getOrFail : xyC:Choice<'a,'b> -> 'a

Full name: Index.Choice.getOrFail
val xyC : Choice<'a,'b>
union case Choice.Choice1Of2: 'T1 -> Choice<'T1,'T2>
val x : 'a
union case Choice.Choice2Of2: 'T2 -> Choice<'T1,'T2>
val y : 'b
val failwithf : format:Printf.StringFormat<'T,'Result> -> 'T

Full name: Microsoft.FSharp.Core.ExtraTopLevelOperators.failwithf
Multiple items
type Uri =
  new : uriString:string -> Uri + 5 overloads
  member AbsolutePath : string
  member AbsoluteUri : string
  member Authority : string
  member DnsSafeHost : string
  member Equals : comparand:obj -> bool
  member Fragment : string
  member GetComponents : components:UriComponents * format:UriFormat -> string
  member GetHashCode : unit -> int
  member GetLeftPart : part:UriPartial -> string
  ...

Full name: System.Uri

--------------------
Uri(uriString: string) : unit
Uri(uriString: string, uriKind: UriKind) : unit
Uri(baseUri: Uri, relativeUri: string) : unit
Uri(baseUri: Uri, relativeUri: Uri) : unit
val isAbsolute : uri:Uri -> bool

Full name: Index.Uri.isAbsolute
val uri : Uri
property Uri.IsAbsoluteUri: bool
val toString : uri:Uri -> string

Full name: Index.Uri.toString
Uri.ToString() : string
namespace HttpFs
namespace HttpFs.Logging
module Global

from HttpFs.Logging
val initialise : cfg:LoggingConfig -> unit

Full name: HttpFs.Logging.Global.initialise
val DefaultConfig : LoggingConfig

Full name: HttpFs.Logging.Global.DefaultConfig
Multiple items
type ConsoleWindowTarget =
  interface Logger
  new : minLevel:LogLevel * ?formatter:(Message -> string) * ?colourise:bool * ?originalColor:ConsoleColor * ?consoleSemaphore:Object -> ConsoleWindowTarget

Full name: HttpFs.Logging.ConsoleWindowTarget

--------------------
new : minLevel:LogLevel * ?formatter:(Message -> string) * ?colourise:bool * ?originalColor:ConsoleColor * ?consoleSemaphore:Object -> ConsoleWindowTarget
union case LogLevel.Verbose: LogLevel
type Logger =
  interface
    abstract member log : LogLevel -> (LogLevel -> Message) -> unit
    abstract member logSimple : Message -> unit
    abstract member logWithAck : LogLevel -> (LogLevel -> Message) -> Async<unit>
  end

Full name: HttpFs.Logging.Logger
module Client

from HttpFs
namespace HttpFs.Auth0
val cp : ClientParams

Full name: Index.cp
Multiple items
union case ClientId.ClientId: string -> ClientId

--------------------
module ClientId

from HttpFs.Auth0.Types

--------------------
type ClientId = | ClientId of string

Full name: HttpFs.Auth0.Types.ClientId
val create : str:string -> ClientId

Full name: HttpFs.Auth0.Types.ClientId.create
val ac : Auth0Credentials

Full name: Index.ac
union case Auth0Credentials.UsernamePassword: connection: string * username: string * password: string -> Auth0Credentials
val atJ : Alt<Choice<Auth0Token,Auth0ApiFailure>>

Full name: Index.atJ
module Authentication

from HttpFs.Auth0
val createRequest : cp:ClientParams -> ac:Auth0Credentials -> Request

Full name: HttpFs.Auth0.Authentication.createRequest
val tryAuthenticate : req:Request -> Alt<Authentication.AuthenticationResult>

Full name: HttpFs.Auth0.Authentication.tryAuthenticate
type Alt<'T> =
  inherit Job<'T>

Full name: Hopac.Alt<_>
val afterFun : ('x -> 'y) -> Alt<'x> -> Alt<'y>

Full name: Hopac.Alt.afterFun
Multiple items
module AuthenticationResult

from HttpFs.Auth0.Authentication

--------------------
type AuthenticationResult =
  | AuthOk of a0token: Auth0Token
  | AuthFail of failure: Auth0ApiFailure

Full name: HttpFs.Auth0.Authentication.AuthenticationResult
val toChoice : ar:Authentication.AuthenticationResult -> Choice<Auth0Token,Auth0ApiFailure>

Full name: HttpFs.Auth0.Authentication.AuthenticationResult.toChoice
val at : Auth0Token

Full name: Index.at
val run : Job<'x> -> 'x

Full name: Hopac.Hopac.run
Multiple items
module Choice

from Index

--------------------
module Choice

from YoLo

--------------------
type Choice<'T1,'T2> =
  | Choice1Of2 of 'T1
  | Choice2Of2 of 'T2

Full name: Microsoft.FSharp.Core.Choice<_,_>

--------------------
type Choice<'T1,'T2,'T3> =
  | Choice1Of3 of 'T1
  | Choice2Of3 of 'T2
  | Choice3Of3 of 'T3

Full name: Microsoft.FSharp.Core.Choice<_,_,_>

--------------------
type Choice<'T1,'T2,'T3,'T4> =
  | Choice1Of4 of 'T1
  | Choice2Of4 of 'T2
  | Choice3Of4 of 'T3
  | Choice4Of4 of 'T4

Full name: Microsoft.FSharp.Core.Choice<_,_,_,_>

--------------------
type Choice<'T1,'T2,'T3,'T4,'T5> =
  | Choice1Of5 of 'T1
  | Choice2Of5 of 'T2
  | Choice3Of5 of 'T3
  | Choice4Of5 of 'T4
  | Choice5Of5 of 'T5

Full name: Microsoft.FSharp.Core.Choice<_,_,_,_,_>

--------------------
type Choice<'T1,'T2,'T3,'T4,'T5,'T6> =
  | Choice1Of6 of 'T1
  | Choice2Of6 of 'T2
  | Choice3Of6 of 'T3
  | Choice4Of6 of 'T4
  | Choice5Of6 of 'T5
  | Choice6Of6 of 'T6

Full name: Microsoft.FSharp.Core.Choice<_,_,_,_,_,_>

--------------------
type Choice<'T1,'T2,'T3,'T4,'T5,'T6,'T7> =
  | Choice1Of7 of 'T1
  | Choice2Of7 of 'T2
  | Choice3Of7 of 'T3
  | Choice4Of7 of 'T4
  | Choice5Of7 of 'T5
  | Choice6Of7 of 'T6
  | Choice7Of7 of 'T7

Full name: Microsoft.FSharp.Core.Choice<_,_,_,_,_,_,_>
val respJ : Alt<Response>

Full name: Index.respJ
Multiple items
module Request

from HttpFs.Client

--------------------
type Request =
  {url: Uri;
   method: HttpMethod;
   cookiesEnabled: bool;
   autoFollowRedirects: bool;
   autoDecompression: DecompressionScheme;
   headers: Map<string,RequestHeader>;
   body: RequestBody;
   bodyCharacterEncoding: Encoding;
   queryStringItems: Map<QueryStringName,QueryStringValue>;
   cookies: Map<CookieName,Cookie>;
   ...}

Full name: HttpFs.Client.Request
val createUrl : httpMethod:HttpMethod -> url:string -> Request

Full name: HttpFs.Client.Request.createUrl
union case HttpMethod.Get: HttpMethod
module Auth0Client

from HttpFs.Auth0
val addAuth0TokenHeader : a0token:Auth0Token -> req:Request -> Request

Full name: HttpFs.Auth0.Auth0Client.addAuth0TokenHeader
val getResponse : request:Request -> Alt<Response>

Full name: HttpFs.Client.getResponse
val cep : CacheExpirationParameters

Full name: Index.cep
Multiple items
module CacheExpirationParameters

from HttpFs.Auth0

--------------------
type CacheExpirationParameters

Full name: HttpFs.Auth0.CacheExpirationParameters
val create' : defaultMaxAge:int64 -> maxAgeOnTimeout:int64 -> MaxAgeOnFailure:int64 -> CacheExpirationParameters

Full name: HttpFs.Auth0.CacheExpirationParameters.create'
val tc : TokenCache

Full name: Index.tc
Multiple items
module TokenCache

from HttpFs.Auth0

--------------------
type TokenCache

Full name: HttpFs.Auth0.TokenCache
val create : unit -> Job<TokenCache>

Full name: HttpFs.Auth0.TokenCache.create
val credentialMap : Map<ClientParams,Auth0Credentials>

Full name: Index.credentialMap
Multiple items
module Map

from YoLo

--------------------
module Map

from Microsoft.FSharp.Collections

--------------------
type Map<'Key,'Value (requires comparison)> =
  interface IEnumerable
  interface IComparable
  interface IEnumerable<KeyValuePair<'Key,'Value>>
  interface ICollection<KeyValuePair<'Key,'Value>>
  interface IDictionary<'Key,'Value>
  new : elements:seq<'Key * 'Value> -> Map<'Key,'Value>
  member Add : key:'Key * value:'Value -> Map<'Key,'Value>
  member ContainsKey : key:'Key -> bool
  override Equals : obj -> bool
  member Remove : key:'Key -> Map<'Key,'Value>
  ...

Full name: Microsoft.FSharp.Collections.Map<_,_>

--------------------
new : elements:seq<'Key * 'Value> -> Map<'Key,'Value>
val ofList : elements:('Key * 'T) list -> Map<'Key,'T> (requires comparison)

Full name: Microsoft.FSharp.Collections.Map.ofList
val prefixWhitelist : (Uri * ClientParams) list

Full name: Index.prefixWhitelist
val tryGetCredentialsJob : uri:Uri -> cp:ClientParams -> Job<Auth0Credentials option>

Full name: Index.tryGetCredentialsJob
val cp : ClientParams
val isWhitelisted : (Uri -> Uri * ClientParams -> ClientParams option)
val whitelistedUri : Uri
val validParams : ClientParams
type ClientParams =
  {AuthenticationHost: string;
   ClientId: ClientId;}

Full name: HttpFs.Auth0.Types.ClientParams
Uri.IsBaseOf(uri: Uri) : bool
union case Option.Some: Value: 'T -> Option<'T>
union case Option.None: Option<'T>
Multiple items
module List

from YoLo

--------------------
module List

from Microsoft.FSharp.Collections

--------------------
type List<'T> =
  | ( [] )
  | ( :: ) of Head: 'T * Tail: 'T list
  interface IEnumerable
  interface IEnumerable<'T>
  member GetSlice : startIndex:int option * endIndex:int option -> 'T list
  member Head : 'T
  member IsEmpty : bool
  member Item : index:int -> 'T with get
  member Length : int
  member Tail : 'T list
  static member Cons : head:'T * tail:'T list -> 'T list
  static member Empty : 'T list

Full name: Microsoft.FSharp.Collections.List<_>
val tryPick : chooser:('T -> 'U option) -> list:'T list -> 'U option

Full name: Microsoft.FSharp.Collections.List.tryPick
Multiple items
module Option

from YoLo

--------------------
module Option

from Microsoft.FSharp.Core
val bind : binder:('T -> 'U option) -> option:'T option -> 'U option

Full name: Microsoft.FSharp.Core.Option.bind
val tryFind : key:'Key -> table:Map<'Key,'T> -> 'T option (requires comparison)

Full name: Microsoft.FSharp.Collections.Map.tryFind
type Job<'T> =

Full name: Hopac.Job<_>
val result : 'x -> Job<'x>

Full name: Hopac.Job.result
val tryAuthenticateClient : uri:Uri -> cp:ClientParams -> Alt<Authentication.AuthenticationResult>

Full name: Index.tryAuthenticateClient
val tryAuthenticateFromSource : ats:(Uri -> ClientParams -> #Job<Auth0Credentials option>) -> uri:Uri -> cp:ClientParams -> Alt<Authentication.AuthenticationResult>

Full name: HttpFs.Auth0.Authentication.tryAuthenticateFromSource
val tryGetAuthToken : uri:Uri -> (ClientParams -> Job<Auth0Token option>)

Full name: Index.tryGetAuthToken
val tryGetTokenWithFill : cep:CacheExpirationParameters -> cp2arJ:(ClientParams -> #Job<Authentication.AuthenticationResult>) -> tc:TokenCache -> cp:ClientParams -> Job<Auth0Token option>

Full name: HttpFs.Auth0.TokenCache.tryGetTokenWithFill
val respCToStringJ : _arg1:Choice<Response,exn> -> Job<string>

Full name: Index.respCToStringJ
val resp : Response
Multiple items
module Response

from HttpFs.Client

--------------------
type Response =
  {statusCode: int;
   contentLength: int64;
   characterSet: CharacterSet;
   cookies: Map<string,string>;
   headers: Map<ResponseHeader,string>;
   expectedEncoding: Encoding option;
   responseUri: Uri;
   body: Stream;
   luggage: IDisposable option;}
  interface IDisposable
  override ToString : unit -> string
  static member private ofHttpResponse : response:HttpWebResponse -> Response

Full name: HttpFs.Client.Response
val readBodyAsString : response:Response -> Job<string>

Full name: HttpFs.Client.Response.readBodyAsString
val ex : exn
Multiple items
val string : value:'T -> string

Full name: Microsoft.FSharp.Core.Operators.string

--------------------
type string = String

Full name: Microsoft.FSharp.Core.string
val respStrA : Alt<string>

Full name: Index.respStrA
val tryGetResponseWithRetryOnAuthRequired : ats:(Uri -> ClientParams -> #Job<Auth0Token option>) -> req:Request -> Alt<Choice<Response,exn>>

Full name: HttpFs.Auth0.Auth0Client.tryGetResponseWithRetryOnAuthRequired
val afterJob : ('x -> #Job<'y>) -> Alt<'x> -> Alt<'y>

Full name: Hopac.Alt.afterJob
type Environment =
  static member CommandLine : string
  static member CurrentDirectory : string with get, set
  static member Exit : exitCode:int -> unit
  static member ExitCode : int with get, set
  static member ExpandEnvironmentVariables : name:string -> string
  static member FailFast : message:string -> unit + 1 overload
  static member GetCommandLineArgs : unit -> string[]
  static member GetEnvironmentVariable : variable:string -> string + 1 overload
  static member GetEnvironmentVariables : unit -> IDictionary + 1 overload
  static member GetFolderPath : folder:SpecialFolder -> string + 1 overload
  ...
  nested type SpecialFolder
  nested type SpecialFolderOption

Full name: System.Environment
namespace Microsoft.FSharp.Core
namespace Microsoft.FSharp
new : unit -> FSharpFunc<'T,'U>
namespace System.Threading
type ExecutionContext =
  member CreateCopy : unit -> ExecutionContext
  member Dispose : unit -> unit
  member GetObjectData : info:SerializationInfo * context:StreamingContext -> unit
  static member Capture : unit -> ExecutionContext
  static member IsFlowSuppressed : unit -> bool
  static member RestoreFlow : unit -> unit
  static member Run : executionContext:ExecutionContext * callback:ContextCallback * state:obj -> unit
  static member SuppressFlow : unit -> AsyncFlowControl

Full name: System.Threading.ExecutionContext
System.Threading.ExecutionContext.Run(executionContext: System.Threading.ExecutionContext, callback: System.Threading.ContextCallback, state: obj) : unit
Fork me on GitHub