2 people like it.
Like the snippet!
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:
139:
140:
|
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
token
httpMethod
baseUrl
reqParams =
let secParams =
[
"oauth_consumer_key", !*consumerKey
"oauth_signature_method" , "HMAC-SHA1"
"oauth_timestamp", timeStamp()
"oauth_token", !*token
"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>"] |> Map.ofList
let authHeader = authHeader signKey consumerKey token 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 -> token: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 token : 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 requestQuery : Map<string,string>
val authHeader : string
More information