2 people like it.

Twitter OAuth

Generates the value string for the "Authorization:" header given Twitter application/user keys and tokens and the parameters for the request being authorized. Slightly updated to allow additional oauth parameters to be included in the header. This version handles the case when the token is not yet available, i.e. when you want to request a new token/token_secret pair.

  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: 
 29: 
 30: 
 31: 
 32: 
 33: 
 34: 
 35: 
 36: 
 37: 
 38: 
 39: 
 40: 
 41: 
 42: 
 43: 
 44: 
 45: 
 46: 
 47: 
 48: 
 49: 
 50: 
 51: 
 52: 
 53: 
 54: 
 55: 
 56: 
 57: 
 58: 
 59: 
 60: 
 61: 
 62: 
 63: 
 64: 
 65: 
 66: 
 67: 
 68: 
 69: 
 70: 
 71: 
 72: 
 73: 
 74: 
 75: 
 76: 
 77: 
 78: 
 79: 
 80: 
 81: 
 82: 
 83: 
 84: 
 85: 
 86: 
 87: 
 88: 
 89: 
 90: 
 91: 
 92: 
 93: 
 94: 
 95: 
 96: 
 97: 
 98: 
 99: 
100: 
101: 
102: 
103: 
104: 
105: 
106: 
107: 
108: 
109: 
110: 
111: 
112: 
113: 
114: 
115: 
116: 
117: 
118: 
119: 
120: 
121: 
122: 
123: 
124: 
125: 
126: 
127: 
128: 
129: 
130: 
131: 
132: 
133: 
134: 
135: 
136: 
137: 
138: 
module TwitterAuth
open System
open System.Text
open System.Net

let percentEncode (sb:StringBuilder) (ch:char) =
    if   '0' <= ch && ch <= '9' then sb.Append(ch)
    elif 'a' <= ch && ch <= 'z' then sb.Append(ch)
    elif 'A' <= ch && ch <= 'Z' then sb.Append(ch)
    else
        match ch with 
        | '-' | '.' | '_'  | '~' -> sb.Append(ch)
        | _ -> 
            sb.Append('%') |> ignore
            sb.AppendFormat("{0:X2}",int(ch))

let (+=) (sb:StringBuilder) (a:string) = sb.Append(a)
let (!*) (s:string) = 
    let sb = StringBuilder()
    for i in 0..s.Length-1 do
        let ch = s.[i]
        percentEncode sb ch |> ignore
    sb.ToString()

let rnd = System.Random()
let nonce() =
    let bytes = Array.create 16 0uy
    rnd.NextBytes(bytes)
    BitConverter.ToString(bytes).Replace("-","")

let epoch = DateTime(1970,1,1)
let timeStamp() =
    let dt = (DateTime.UtcNow - epoch).TotalSeconds |> int
    dt.ToString()

let toUpper (s:string) = s.ToUpper()

let signingKey (consumerSecret:string) tokenSecret = 
    consumerSecret + "&" + tokenSecret
    |> Encoding.ASCII.GetBytes

let parameterString parameters =
    let amp = "&"
    let eq  = "="
    let sb = (new StringBuilder(), parameters) ||> Map.fold (fun sb k v -> sb += k += eq += v += amp)
    sb.Remove(sb.Length-amp.Length,amp.Length).ToString()

let sigBase httpMethod baseUrl parmDataStr = 
    (httpMethod |> toUpper) + "&" + !* baseUrl + "&" + !* parmDataStr

let hmacSha1Sig signKey dataString =
    let data = (dataString:string) |> Encoding.ASCII.GetBytes
    use alg = new System.Security.Cryptography.HMACSHA1(signKey)
    alg.ComputeHash(data) |> Convert.ToBase64String

let buildAuthHdr headerParameters =
    assert (headerParameters |> Map.toSeq |> Seq.length = 7)
    let sb = StringBuilder()
    sb.Append("OAuth ") |> ignore
    let sb = (sb,headerParameters) ||> Map.fold (fun sb k v -> sb += k += "=" += "\"" += v += "\"" += ", ")
    sb.Remove(sb.Length - 2, 2) |> ignore
    let header = sb.ToString()
    header

///Generate the Authorization header string based on the request parameters and keys and tokens
//The process is defined here: https://dev.twitter.com/docs/auth/authorizing-request
let authHeader 
    signKey
    consumerKey
    httpMethod
    baseUrl
    reqParams =
    let secParams =
        [
            "oauth_consumer_key",           !*consumerKey
            "oauth_signature_method" ,      "HMAC-SHA1"
            "oauth_timestamp",              timeStamp()
            "oauth_version",                "1.0"
            "oauth_nonce",                  nonce()
        ] |> Map.ofList   
    let parameters = (secParams,reqParams) ||> Map.fold(fun acc k v -> acc|>Map.add !*k !*v)
    let parmStr = parameters |> parameterString
    let data2Sign = sigBase httpMethod baseUrl parmStr
    let sigData = hmacSha1Sig signKey data2Sign
    let headerParameters = 
        parameters 
        |> Map.filter (fun k _ -> k.StartsWith("oauth_") || k="realm")
        |> Map.add "oauth_signature" !*sigData
    buildAuthHdr headerParameters

//test parameters are from here
//https://dev.twitter.com/docs/auth/creating-signature
let testSig() =
    let parameters = 
        [
            "status",                       "Hello Ladies + Gentlemen, a signed OAuth request!"
            "include_entities",             "true"
            "oauth_consumer_key",           "xvz1evFS4wEEPTGEFPHBog"
            "oauth_nonce",                  "88643f5b760c4780814a7101ef796851"
            "oauth_signature_method" ,      "HMAC-SHA1"
            "oauth_timestamp",              "1318622958"
            "oauth_token",                  "370773112-GmHxMAgYyLbNEtIKZeRNFsMKPR9EyMZeS9weJAEb"
            "oauth_version",                "1.0"
        ]
        |> List.map (fun (k,v) -> !*k,!*v)
        |> Map.ofList
    let consumerSecret = "kAcSOqF21Fu85e7zjz7ZN2U4ZRhfV3WpwPAoE3Z7kBw"
    let tokenSecret = "LswwdoUaIvS8ltyTt5jkRh4J50vUPVVHtR2YPi5kE"
    let signKey = signingKey consumerSecret tokenSecret
    let httpMethod = "post"
    let baseUrl = "https://api.twitter.com/1/statuses/update.json"
    let parmStr = parameters |> parameterString
    let data = sigBase httpMethod baseUrl parmStr
    let mySig = hmacSha1Sig signKey data
    mySig

let toParmString parms =
    let sb = (StringBuilder(),parms) ||> Map.fold (fun sb k v -> sb += !*k += "=" += !*v += "&")
    sb.Remove(sb.Length-1,1).ToString()

let download (url:string) hdr =
    use wc = new WebClient()
    wc.Headers.Add(HttpRequestHeader.Authorization,hdr)
    wc.DownloadString(url)

//substitute where you see '****' with appropriate values, to test your keys and tokens
let myExample() =
    let consumerKey = "<****my consumer key"
    let consumerSecret = "<****my consumer secret>"
    let token = "<****my access token>"
    let tokenSecret = "<****my token secret>"
    let signKey = signingKey consumerSecret tokenSecret
    let baseUrl = "https://api.twitter.com/1.1/statuses/user_timeline.json"
    let httpMethod = "get"
    let requestQuery = ["user_id", "<****my userid>"; "oauth_token", "<****my token>"] |> Map.ofList
    let authHeader = authHeader signKey consumerKey httpMethod baseUrl requestQuery
    let url = baseUrl + "?" + (requestQuery |> toParmString)
    download url authHeader
module TwitterAuth
namespace System
namespace System.Text
namespace System.Net
val percentEncode : sb:StringBuilder -> ch:char -> StringBuilder

Full name: TwitterAuth.percentEncode
val sb : StringBuilder
Multiple items
type StringBuilder =
  new : unit -> StringBuilder + 5 overloads
  member Append : value:string -> StringBuilder + 18 overloads
  member AppendFormat : format:string * arg0:obj -> StringBuilder + 4 overloads
  member AppendLine : unit -> StringBuilder + 1 overload
  member Capacity : int with get, set
  member Chars : int -> char with get, set
  member Clear : unit -> StringBuilder
  member CopyTo : sourceIndex:int * destination:char[] * destinationIndex:int * count:int -> unit
  member EnsureCapacity : capacity:int -> int
  member Equals : sb:StringBuilder -> bool
  ...

Full name: System.Text.StringBuilder

--------------------
StringBuilder() : unit
StringBuilder(capacity: int) : unit
StringBuilder(value: string) : unit
StringBuilder(value: string, capacity: int) : unit
StringBuilder(capacity: int, maxCapacity: int) : unit
StringBuilder(value: string, startIndex: int, length: int, capacity: int) : unit
val ch : char
Multiple items
val char : value:'T -> char (requires member op_Explicit)

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

--------------------
type char = Char

Full name: Microsoft.FSharp.Core.char
StringBuilder.Append(value: char []) : StringBuilder
   (+0 other overloads)
StringBuilder.Append(value: obj) : StringBuilder
   (+0 other overloads)
StringBuilder.Append(value: uint64) : StringBuilder
   (+0 other overloads)
StringBuilder.Append(value: uint32) : StringBuilder
   (+0 other overloads)
StringBuilder.Append(value: uint16) : StringBuilder
   (+0 other overloads)
StringBuilder.Append(value: decimal) : StringBuilder
   (+0 other overloads)
StringBuilder.Append(value: float) : StringBuilder
   (+0 other overloads)
StringBuilder.Append(value: float32) : StringBuilder
   (+0 other overloads)
StringBuilder.Append(value: int64) : StringBuilder
   (+0 other overloads)
StringBuilder.Append(value: int) : StringBuilder
   (+0 other overloads)
val ignore : value:'T -> unit

Full name: Microsoft.FSharp.Core.Operators.ignore
StringBuilder.AppendFormat(format: string, [<ParamArray>] args: obj []) : StringBuilder
StringBuilder.AppendFormat(format: string, arg0: obj) : StringBuilder
StringBuilder.AppendFormat(provider: IFormatProvider, format: string, [<ParamArray>] args: obj []) : StringBuilder
StringBuilder.AppendFormat(format: string, arg0: obj, arg1: obj) : StringBuilder
StringBuilder.AppendFormat(format: string, arg0: obj, arg1: obj, arg2: obj) : StringBuilder
Multiple items
val int : value:'T -> int (requires member op_Explicit)

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

--------------------
type int = int32

Full name: Microsoft.FSharp.Core.int

--------------------
type int<'Measure> = int

Full name: Microsoft.FSharp.Core.int<_>
val a : string
Multiple items
val string : value:'T -> string

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

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

Full name: Microsoft.FSharp.Core.string
val s : string
val i : int32
property String.Length: int
StringBuilder.ToString() : string
StringBuilder.ToString(startIndex: int, length: int) : string
val rnd : Random

Full name: TwitterAuth.rnd
Multiple items
type Random =
  new : unit -> Random + 1 overload
  member Next : unit -> int + 2 overloads
  member NextBytes : buffer:byte[] -> unit
  member NextDouble : unit -> float

Full name: System.Random

--------------------
Random() : unit
Random(Seed: int) : unit
val nonce : unit -> string

Full name: TwitterAuth.nonce
val bytes : byte []
type Array =
  member Clone : unit -> obj
  member CopyTo : array:Array * index:int -> unit + 1 overload
  member GetEnumerator : unit -> IEnumerator
  member GetLength : dimension:int -> int
  member GetLongLength : dimension:int -> int64
  member GetLowerBound : dimension:int -> int
  member GetUpperBound : dimension:int -> int
  member GetValue : [<ParamArray>] indices:int[] -> obj + 7 overloads
  member Initialize : unit -> unit
  member IsFixedSize : bool
  ...

Full name: System.Array
val create : count:int -> value:'T -> 'T []

Full name: Microsoft.FSharp.Collections.Array.create
Random.NextBytes(buffer: byte []) : unit
type BitConverter =
  static val IsLittleEndian : bool
  static member DoubleToInt64Bits : value:float -> int64
  static member GetBytes : value:bool -> byte[] + 9 overloads
  static member Int64BitsToDouble : value:int64 -> float
  static member ToBoolean : value:byte[] * startIndex:int -> bool
  static member ToChar : value:byte[] * startIndex:int -> char
  static member ToDouble : value:byte[] * startIndex:int -> float
  static member ToInt16 : value:byte[] * startIndex:int -> int16
  static member ToInt32 : value:byte[] * startIndex:int -> int
  static member ToInt64 : value:byte[] * startIndex:int -> int64
  ...

Full name: System.BitConverter
BitConverter.ToString(value: byte []) : string
BitConverter.ToString(value: byte [], startIndex: int) : string
BitConverter.ToString(value: byte [], startIndex: int, length: int) : string
val epoch : DateTime

Full name: TwitterAuth.epoch
Multiple items
type DateTime =
  struct
    new : ticks:int64 -> DateTime + 10 overloads
    member Add : value:TimeSpan -> DateTime
    member AddDays : value:float -> DateTime
    member AddHours : value:float -> DateTime
    member AddMilliseconds : value:float -> DateTime
    member AddMinutes : value:float -> DateTime
    member AddMonths : months:int -> DateTime
    member AddSeconds : value:float -> DateTime
    member AddTicks : value:int64 -> DateTime
    member AddYears : value:int -> DateTime
    ...
  end

Full name: System.DateTime

--------------------
DateTime()
   (+0 other overloads)
DateTime(ticks: int64) : unit
   (+0 other overloads)
DateTime(ticks: int64, kind: DateTimeKind) : unit
   (+0 other overloads)
DateTime(year: int, month: int, day: int) : unit
   (+0 other overloads)
DateTime(year: int, month: int, day: int, calendar: Globalization.Calendar) : unit
   (+0 other overloads)
DateTime(year: int, month: int, day: int, hour: int, minute: int, second: int) : unit
   (+0 other overloads)
DateTime(year: int, month: int, day: int, hour: int, minute: int, second: int, kind: DateTimeKind) : unit
   (+0 other overloads)
DateTime(year: int, month: int, day: int, hour: int, minute: int, second: int, calendar: Globalization.Calendar) : unit
   (+0 other overloads)
DateTime(year: int, month: int, day: int, hour: int, minute: int, second: int, millisecond: int) : unit
   (+0 other overloads)
DateTime(year: int, month: int, day: int, hour: int, minute: int, second: int, millisecond: int, kind: DateTimeKind) : unit
   (+0 other overloads)
val timeStamp : unit -> string

Full name: TwitterAuth.timeStamp
val dt : int
property DateTime.UtcNow: DateTime
Int32.ToString() : string
Int32.ToString(provider: IFormatProvider) : string
Int32.ToString(format: string) : string
Int32.ToString(format: string, provider: IFormatProvider) : string
val toUpper : s:string -> string

Full name: TwitterAuth.toUpper
String.ToUpper() : string
String.ToUpper(culture: Globalization.CultureInfo) : string
val signingKey : consumerSecret:string -> tokenSecret:string -> byte []

Full name: TwitterAuth.signingKey
val consumerSecret : string
val tokenSecret : string
type Encoding =
  member BodyName : string
  member Clone : unit -> obj
  member CodePage : int
  member DecoderFallback : DecoderFallback with get, set
  member EncoderFallback : EncoderFallback with get, set
  member EncodingName : string
  member Equals : value:obj -> bool
  member GetByteCount : chars:char[] -> int + 3 overloads
  member GetBytes : chars:char[] -> byte[] + 5 overloads
  member GetCharCount : bytes:byte[] -> int + 2 overloads
  ...

Full name: System.Text.Encoding
property Encoding.ASCII: Encoding
Encoding.GetBytes(s: string) : byte []
Encoding.GetBytes(chars: char []) : byte []
Encoding.GetBytes(chars: char [], index: int, count: int) : byte []
Encoding.GetBytes(chars: nativeptr<char>, charCount: int, bytes: nativeptr<byte>, byteCount: int) : int
Encoding.GetBytes(s: string, charIndex: int, charCount: int, bytes: byte [], byteIndex: int) : int
Encoding.GetBytes(chars: char [], charIndex: int, charCount: int, bytes: byte [], byteIndex: int) : int
val parameterString : parameters:Map<string,string> -> string

Full name: TwitterAuth.parameterString
val parameters : Map<string,string>
val amp : string
val eq : string
Multiple items
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 fold : folder:('State -> 'Key -> 'T -> 'State) -> state:'State -> table:Map<'Key,'T> -> 'State (requires comparison)

Full name: Microsoft.FSharp.Collections.Map.fold
val k : string
val v : string
StringBuilder.Remove(startIndex: int, length: int) : StringBuilder
property StringBuilder.Length: int
val sigBase : httpMethod:string -> baseUrl:string -> parmDataStr:string -> string

Full name: TwitterAuth.sigBase
val httpMethod : string
val baseUrl : string
val parmDataStr : string
val hmacSha1Sig : signKey:byte [] -> dataString:string -> string

Full name: TwitterAuth.hmacSha1Sig
val signKey : byte []
val dataString : string
val data : byte []
val alg : Security.Cryptography.HMACSHA1
namespace System.Security
namespace System.Security.Cryptography
Multiple items
type HMACSHA1 =
  inherit HMAC
  new : unit -> HMACSHA1 + 2 overloads

Full name: System.Security.Cryptography.HMACSHA1

--------------------
Security.Cryptography.HMACSHA1() : unit
Security.Cryptography.HMACSHA1(key: byte []) : unit
Security.Cryptography.HMACSHA1(key: byte [], useManagedSha1: bool) : unit
Security.Cryptography.HashAlgorithm.ComputeHash(buffer: byte []) : byte []
Security.Cryptography.HashAlgorithm.ComputeHash(inputStream: IO.Stream) : byte []
Security.Cryptography.HashAlgorithm.ComputeHash(buffer: byte [], offset: int, count: int) : byte []
type Convert =
  static val DBNull : obj
  static member ChangeType : value:obj * typeCode:TypeCode -> obj + 3 overloads
  static member FromBase64CharArray : inArray:char[] * offset:int * length:int -> byte[]
  static member FromBase64String : s:string -> byte[]
  static member GetTypeCode : value:obj -> TypeCode
  static member IsDBNull : value:obj -> bool
  static member ToBase64CharArray : inArray:byte[] * offsetIn:int * length:int * outArray:char[] * offsetOut:int -> int + 1 overload
  static member ToBase64String : inArray:byte[] -> string + 3 overloads
  static member ToBoolean : value:obj -> bool + 17 overloads
  static member ToByte : value:obj -> byte + 18 overloads
  ...

Full name: System.Convert
Convert.ToBase64String(inArray: byte []) : string
Convert.ToBase64String(inArray: byte [], options: Base64FormattingOptions) : string
Convert.ToBase64String(inArray: byte [], offset: int, length: int) : string
Convert.ToBase64String(inArray: byte [], offset: int, length: int, options: Base64FormattingOptions) : string
val buildAuthHdr : headerParameters:Map<string,string> -> string

Full name: TwitterAuth.buildAuthHdr
val headerParameters : Map<string,string>
val toSeq : table:Map<'Key,'T> -> seq<'Key * 'T> (requires comparison)

Full name: Microsoft.FSharp.Collections.Map.toSeq
module Seq

from Microsoft.FSharp.Collections
val length : source:seq<'T> -> int

Full name: Microsoft.FSharp.Collections.Seq.length
val header : string
val authHeader : signKey:byte [] -> consumerKey:string -> httpMethod:string -> baseUrl:string -> reqParams:Map<string,string> -> string

Full name: TwitterAuth.authHeader


Generate the Authorization header string based on the request parameters and keys and tokens
val consumerKey : string
val reqParams : Map<string,string>
val secParams : Map<string,string>
val ofList : elements:('Key * 'T) list -> Map<'Key,'T> (requires comparison)

Full name: Microsoft.FSharp.Collections.Map.ofList
val acc : Map<string,string>
val add : key:'Key -> value:'T -> table:Map<'Key,'T> -> Map<'Key,'T> (requires comparison)

Full name: Microsoft.FSharp.Collections.Map.add
val parmStr : string
val data2Sign : string
val sigData : string
val filter : predicate:('Key -> 'T -> bool) -> table:Map<'Key,'T> -> Map<'Key,'T> (requires comparison)

Full name: Microsoft.FSharp.Collections.Map.filter
String.StartsWith(value: string) : bool
String.StartsWith(value: string, comparisonType: StringComparison) : bool
String.StartsWith(value: string, ignoreCase: bool, culture: Globalization.CultureInfo) : bool
val testSig : unit -> string

Full name: TwitterAuth.testSig
Multiple items
module List

from Microsoft.FSharp.Collections

--------------------
type List<'T> =
  | ( [] )
  | ( :: ) of Head: 'T * Tail: 'T list
  interface IEnumerable
  interface IEnumerable<'T>
  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 map : mapping:('T -> 'U) -> list:'T list -> 'U list

Full name: Microsoft.FSharp.Collections.List.map
val data : string
val mySig : string
val toParmString : parms:Map<string,string> -> string

Full name: TwitterAuth.toParmString
val parms : Map<string,string>
val download : url:string -> hdr:string -> string

Full name: TwitterAuth.download
val url : string
val hdr : string
val wc : WebClient
Multiple items
type WebClient =
  inherit Component
  new : unit -> WebClient
  member BaseAddress : string with get, set
  member CachePolicy : RequestCachePolicy with get, set
  member CancelAsync : unit -> unit
  member Credentials : ICredentials with get, set
  member DownloadData : address:string -> byte[] + 1 overload
  member DownloadDataAsync : address:Uri -> unit + 1 overload
  member DownloadFile : address:string * fileName:string -> unit + 1 overload
  member DownloadFileAsync : address:Uri * fileName:string -> unit + 1 overload
  member DownloadString : address:string -> string + 1 overload
  ...

Full name: System.Net.WebClient

--------------------
WebClient() : unit
property WebClient.Headers: WebHeaderCollection
Collections.Specialized.NameValueCollection.Add(c: Collections.Specialized.NameValueCollection) : unit
WebHeaderCollection.Add(header: string) : unit
WebHeaderCollection.Add(name: string, value: string) : unit
WebHeaderCollection.Add(header: HttpResponseHeader, value: string) : unit
WebHeaderCollection.Add(header: HttpRequestHeader, value: string) : unit
type HttpRequestHeader =
  | CacheControl = 0
  | Connection = 1
  | Date = 2
  | KeepAlive = 3
  | Pragma = 4
  | Trailer = 5
  | TransferEncoding = 6
  | Upgrade = 7
  | Via = 8
  | Warning = 9
  ...

Full name: System.Net.HttpRequestHeader
field HttpRequestHeader.Authorization = 24
WebClient.DownloadString(address: Uri) : string
WebClient.DownloadString(address: string) : string
val myExample : unit -> string

Full name: TwitterAuth.myExample
val token : string
val requestQuery : Map<string,string>
val authHeader : string

More information

Link:http://fssnip.net/dW
Posted:11 years ago
Author:Faisal Waris
Tags: twitter; authorization