I'm trying to use JWT authentication in Box using a key pair to get an access token, but am stuck creating the JWT assertion
Documentation I'm trying to follow:
https://developer.box.com/guides/authentication/jwt/without-sdk/
Any help is appreciated.
This works using a temporary developer token:
Code: Select all
EndPointBox = https://api.box.com/2.0/folders/0/items
Payload =
access_token = ######(Temp Dev Token)######
Reg:=API_Call_Box("GET",EndpointBox,access_token,Payload)
FolderCount := Reg.total_count
API_Call_Box(Type,EndpointBox,access_token,Payload){
HTTP := ComObjCreate("WinHttp.WinHttpRequest.5.1")
HTTP.Open(Type,EndPointBox)
HTTP.SetRequestHeader("Authorization","Bearer " access_token)
HTTP.SetRequestHeader("Content-Type","application/json")
HTTP.Send()
;HTTPstatus := HTTP.Status
;HTTPresponse := HTTP.ResponseText
;msgbox % HTTPstatus
;msgbox % HTTPresponse
ParsedResponse:=json(HTTP.ResponseText)
Return ParsedResponse
}
msgbox % FolderCount
ExitApp
;;;;;;;;json;;;;;;;;
json(json, rec := false) {
static doc := ComObjCreate("htmlfile")
, __ := doc.write("<meta http-equiv=""X-UA-Compatible"" content=""IE=9"">")
, JS := doc.parentWindow
if !rec
obj := %A_ThisFunc%(JS.eval("(" . json . ")"), true)
else if !IsObject(json)
obj := json
else if JS.Object.prototype.toString.call(json) == "[object Array]" {
obj := []
Loop % json.length
obj.Push( %A_ThisFunc%(json[A_Index - 1], true) )
}
else {
obj := {}
keys := JS.Object.keys(json)
Loop % keys.length {
k := keys[A_Index - 1]
obj[k] := %A_ThisFunc%(json[k], true)
}
}
Return obj
}
My attempt at generating an access token:
Code: Select all
#NoEnv
#SingleInstance,Force
SetBatchLines, -1
;;;;;;;;;;;;;;;;;;;;;;;;;;;Get-Token;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;https://developer.box.com/guides/authentication/jwt/without-sdk/
clientID := "#############"
clientSecret := "#####################"
enterpriseID := "##############"
publicKeyID := "###############"
;privateKey := "-----BEGIN ENCRYPTED PRIVATE KEY-----\n######################\n-----END ENCRYPTED PRIVATE KEY-----\n"
privateKey := "############################"
passphrase := "#######################"
time := A_now
time += 45, s
random, RandomNum, 1000000000000000000.0, 9999999999999999999.0
RandomNum := floor(RandomNum)
authenticationUrl := "https://api.box.com/oauth2/token"
key := AES.Decrypt(privateKey, passphrase, "256")
claims := QueryString_Builder({"iss":clientID,"sub":enterpriseID,"box_sub_type":"enterprise","aud":authenticationUrl,"jti":RandomNum,"exp":time,"kid":publicKeyID})
;Create JWT Assertion?
assertion := ???????(claims, key, "RS512")
params := QueryString_Builder({"grant_type":"urn:ietf:params:oauth:grant-type:jwt-bearer","assertion":assertion,"client_id":clientID,"client_secret":clientSecret})
HTTP := ComObjCreate("WinHttp.WinHttpRequest.5.1")
HTTP.Open("POST",authenticationUrl . params)
HTTP.Send()
response := HTTP.ResponseText
access_token := json(response)
msgbox % access_token
;;;;;;;;;;;;;;;;;;;;;;;;;;;Get-Data;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
EndPointBox = https://api.box.com/2.0/folders/0/items
Payload =
Reg:=API_Call_Box("GET",EndpointBox,access_token,Payload)
FolderCount := Reg.total_count
API_Call_Box(Type,EndpointBox,access_token,Payload){
HTTP := ComObjCreate("WinHttp.WinHttpRequest.5.1")
HTTP.Open(Type,EndPointBox)
HTTP.SetRequestHeader("Authorization","Bearer " access_token)
HTTP.SetRequestHeader("Content-Type","application/json")
HTTP.Send()
;HTTPstatus := HTTP.Status
;HTTPresponse := HTTP.ResponseText
;msgbox % HTTPstatus
;msgbox % HTTPresponse
ParsedResponse:=json(HTTP.ResponseText)
Return ParsedResponse
}
msgbox % FolderCount
ExitApp
;;;\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
;;;\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\REFERENCE///////////////////////////////////////////////////////////////////////
;;;////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
;;;;;;;;;;;;;;;;;;;;;;;;;;;;QueryString_Builder;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
QueryString_Builder(kvp){
for key, value in kvp
queryString.=((A_Index="1")?(url "?"):("&")) key "=" value
return queryString
}
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AES;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;https://gist.github.com/jNizM/79aa6a4b8ec428bf780f
Class AES
{
Encrypt(string, password, alg)
{
len := this.StrPutVar(string, str_buf, 0, "UTF-16")
this.Crypt(str_buf, len, password, alg, 1)
return this.b64Encode(str_buf, len)
}
Decrypt(string, password, alg)
{
len := this.b64Decode(string, encr_Buf)
sLen := this.Crypt(encr_Buf, len, password, alg, 0)
sLen /= 2
return StrGet(&encr_Buf, sLen, "UTF-16")
}
Crypt(ByRef encr_Buf, ByRef Buf_Len, password, ALG_ID, CryptMode := 1)
{
; WinCrypt.h
static MS_ENH_RSA_AES_PROV := "Microsoft Enhanced RSA and AES Cryptographic Provider"
static PROV_RSA_AES := 24
static CRYPT_VERIFYCONTEXT := 0xF0000000
static CALG_SHA1 := 0x00008004
static CALG_SHA_256 := 0x0000800c
static CALG_SHA_384 := 0x0000800d
static CALG_SHA_512 := 0x0000800e
static CALG_AES_128 := 0x0000660e ; KEY_LENGHT := 0x80 ; (128)
static CALG_AES_192 := 0x0000660f ; KEY_LENGHT := 0xC0 ; (192)
static CALG_AES_256 := 0x00006610 ; KEY_LENGHT := 0x100 ; (256)
static KP_BLOCKLEN := 8
if !(DllCall("advapi32.dll\CryptAcquireContext", "Ptr*", hProv, "Ptr", 0, "Ptr", 0, "Uint", PROV_RSA_AES, "UInt", CRYPT_VERIFYCONTEXT))
MsgBox % "*CryptAcquireContext (" DllCall("kernel32.dll\GetLastError") ")"
if !(DllCall("advapi32.dll\CryptCreateHash", "Ptr", hProv, "Uint", CALG_SHA1, "Ptr", 0, "Uint", 0, "Ptr*", hHash))
MsgBox % "*CryptCreateHash (" DllCall("kernel32.dll\GetLastError") ")"
passLen := this.StrPutVar(password, passBuf, 0, "UTF-16")
if !(DllCall("advapi32.dll\CryptHashData", "Ptr", hHash, "Ptr", &passBuf, "Uint", passLen, "Uint", 0))
MsgBox % "*CryptHashData (" DllCall("kernel32.dll\GetLastError") ")"
if !(DllCall("advapi32.dll\CryptDeriveKey", "Ptr", hProv, "Uint", CALG_AES_%ALG_ID%, "Ptr", hHash, "Uint", (ALG_ID << 0x10), "Ptr*", hKey)) ; KEY_LENGHT << 0x10
MsgBox % "*CryptDeriveKey (" DllCall("kernel32.dll\GetLastError") ")"
if !(DllCall("advapi32.dll\CryptGetKeyParam", "Ptr", hKey, "Uint", KP_BLOCKLEN, "Uint*", BlockLen, "Uint*", 4, "Uint", 0))
MsgBox % "*CryptGetKeyParam (" DllCall("kernel32.dll\GetLastError") ")"
BlockLen /= 8
if (CryptMode)
DllCall("advapi32.dll\CryptEncrypt", "Ptr", hKey, "Ptr", 0, "Uint", 1, "Uint", 0, "Ptr", &encr_Buf, "Uint*", Buf_Len, "Uint", Buf_Len + BlockLen)
else
DllCall("advapi32.dll\CryptDecrypt", "Ptr", hKey, "Ptr", 0, "Uint", 1, "Uint", 0, "Ptr", &encr_Buf, "Uint*", Buf_Len)
DllCall("advapi32.dll\CryptDestroyKey", "Ptr", hKey)
DllCall("advapi32.dll\CryptDestroyHash", "Ptr", hHash)
DllCall("advapi32.dll\CryptReleaseContext", "Ptr", hProv, "UInt", 0)
return Buf_Len
}
StrPutVar(string, ByRef var, addBufLen := 0, encoding := "UTF-16")
{
tlen := ((encoding = "UTF-16" || encoding = "CP1200") ? 2 : 1)
str_len := StrPut(string, encoding) * tlen
VarSetCapacity(var, str_len + addBufLen, 0)
StrPut(string, &var, encoding)
return str_len - tlen
}
b64Encode(ByRef VarIn, SizeIn)
{
static CRYPT_STRING_BASE64 := 0x00000001
static CRYPT_STRING_NOCRLF := 0x40000000
DllCall("crypt32.dll\CryptBinaryToStringA", "Ptr", &VarIn, "UInt", SizeIn, "Uint", (CRYPT_STRING_BASE64 | CRYPT_STRING_NOCRLF), "Ptr", 0, "UInt*", SizeOut)
VarSetCapacity(VarOut, SizeOut, 0)
DllCall("crypt32.dll\CryptBinaryToStringA", "Ptr", &VarIn, "UInt", SizeIn, "Uint", (CRYPT_STRING_BASE64 | CRYPT_STRING_NOCRLF), "Ptr", &VarOut, "UInt*", SizeOut)
return StrGet(&VarOut, SizeOut, "CP0")
}
b64Decode(ByRef VarIn, ByRef VarOut)
{
static CRYPT_STRING_BASE64 := 0x00000001
static CryptStringToBinary := "CryptStringToBinary" (A_IsUnicode ? "W" : "A")
DllCall("crypt32.dll\" CryptStringToBinary, "Ptr", &VarIn, "UInt", 0, "Uint", CRYPT_STRING_BASE64, "Ptr", 0, "UInt*", SizeOut, "Ptr", 0, "Ptr", 0)
VarSetCapacity(VarOut, SizeOut, 0)
DllCall("crypt32.dll\" CryptStringToBinary, "Ptr", &VarIn, "UInt", 0, "Uint", CRYPT_STRING_BASE64, "Ptr", &VarOut, "UInt*", SizeOut, "Ptr", 0, "Ptr", 0)
return SizeOut
}
}
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;json;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
json(json, rec := false) {
static doc := ComObjCreate("htmlfile")
, __ := doc.write("<meta http-equiv=""X-UA-Compatible"" content=""IE=9"">")
, JS := doc.parentWindow
if !rec
obj := %A_ThisFunc%(JS.eval("(" . json . ")"), true)
else if !IsObject(json)
obj := json
else if JS.Object.prototype.toString.call(json) == "[object Array]" {
obj := []
Loop % json.length
obj.Push( %A_ThisFunc%(json[A_Index - 1], true) )
}
else {
obj := {}
keys := JS.Object.keys(json)
Loop % keys.length {
k := keys[A_Index - 1]
obj[k] := %A_ThisFunc%(json[k], true)
}
}
Return obj
}