Last active
January 8, 2020 18:03
-
-
Save MorningZ/df3775548b61fd6a5124a72b85999389 to your computer and use it in GitHub Desktop.
Create Adobe.IO token via VB.NET
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
' What a maddening experience, but was able to get it working! | |
' The following functions will take your Adobe.IO service application settings and generate a token using JWT | |
' You first need to generate a JWT and then "exchange" this for a Bearer token. Your milage may vary | |
' but I created the JWT with an expiration date of 20 mins and then cached the Bearer token for 10 mins, | |
' this way I am using the HttpRuntime cache to handle "refreshing" the Bearer token. | |
' | |
' Notes: | |
' -- Adobe IO Console, create service applications here: https://console.adobe.io/ | |
' -- Service Account Creation walkthrough | |
' https://www.adobe.io/authentication/auth-methods.html#!AdobeDocs/adobeio-auth/master/AuthenticationOverview/ServiceAccountIntegration.md | |
' -- Please store your credentials in a safe way! This example code in | |
' no way should be the way you do this, it is only this simple for demonstration sake. | |
' -- Code is working against .NET Framework 4.6.1, version 4.5.x doesn't have GetRSAPrivateKey method on X509 object | |
' -- I followed along with this code (althouugh this is just half of it), including the two commands for OpenSSL | |
' https://github.com/AdobeDocs/adobeio-auth/tree/stage/JWT/samples/adobe-jwt-dotnet | |
' -- I used OpenSSL 64-bit installer on a Windows 10 Pro machine to generate the key according to these instructions | |
' https://github.com/AdobeDocs/adobeio-auth/tree/stage/JWT/samples/adobe-jwt-dotnet | |
' -- Used Jose.JWT library to create the JWT and RestSharp for calls, installed via NuGet | |
' https://www.nuget.org/packages/jose-jwt/ | |
' https://www.nuget.org/packages/RestSharp | |
''' <summary>Tries to pull an Adobe.IO token from cache</summary> | |
''' <returns> | |
''' Dictionary<String, Object>: | |
''' -- cache:boolean -> indicates if the token was pulled from cache or not | |
''' -- access_token:string -> actual value to use for "Authorization: Bearer <access_token>" | |
''' -- error:boolean -> an error was encountered while retrieving the token | |
''' -- message:string -> if an error was encountered, this will describe error | |
''' </returns> | |
Private Shared Function Get_Token() As Dictionary(Of String, Object) | |
Return Get_Token(False) | |
End Function | |
Private Shared Function Get_Token(ByVal bypass_cache As Boolean) As Dictionary(Of String, Object) | |
Dim RetVal As Dictionary(Of String, Object) = HttpRuntime.Cache.Get("Adobe.IO.Token") | |
If IsNothing(RetVal) OrElse bypass_cache Then | |
' Not in cache or requested to bypass, so generate the token using JWT | |
RetVal = Get_Token_Genetate() | |
RetVal.Add("cache", False) | |
' Put in cache for 10 mins | |
HttpRuntime.Cache.Add("Adobe.IO.Token", RetVal, Nothing, Now().AddMinutes(20), TimeSpan.Zero, Caching.CacheItemPriority.Normal, Nothing) | |
Else | |
RetVal.Add("cache", True) | |
End If | |
Return RetVal | |
End Function | |
''' <summary>Reaches out to Adobe.IO for a token</summary> | |
Private Shared Function Get_Token_Genetate() As Dictionary(Of String, Object) | |
Dim RetVal As Dictionary(Of String, Object) = New Dictionary(Of String, Object) | |
RetVal.Add("error", False) : RetVal.Add("message", String.Empty) | |
' Location of the pfx file (make sure the user that .NET framework runs as has read permissions) | |
Dim ThisPfxFilePath As String = "<full path to pfx file generated by OpenSSL" | |
If Not IO.File.Exists(ThisPfxFilePath) Then | |
RetVal.Item("error") = True | |
RetVal.Item("message") = "Private Key file does not exist" | |
Return RetVal | |
End If | |
' Key to verify the pfx file | |
Dim CertPfxSecret As String = "<Password specified while creating pfx file in OpenSSL>" | |
' Client ID for Adobe.IO | |
Dim ThisClientKey As String = "<API Key (Client ID) specified in Adobe.IO console>" | |
' Client Password for Adobe.IO | |
Dim ThisSecret As String = "<Client secret specified in Adobe.IO console>" | |
' Payload for creating a JWT using Jose.JWT library | |
Dim ThisPayload As Dictionary(Of Object, Object) = New Dictionary(Of Object, Object)() | |
ThisPayload.Add("exp", DateTimeOffset.Now.ToUnixTimeSeconds() + 1200) ' JWT expiration: 20 mins out | |
ThisPayload.Add("iss", "<Organization ID specified in Adobe.IO console>") | |
ThisPayload.Add("sub", "<Technical account ID specidied in Adobe.IO console>") | |
ThisPayload.Add("aud", String.Concat("https://ims-na1.adobelogin.com/c/", ThisClientKey)) | |
' This is the "scope" to use the User Management endpoints, refer to Adobe.IO docs for other endpoints | |
' https://www.adobe.io/authentication/auth-methods.html#!AdobeDocs/adobeio-auth/master/JWT/Scopes.md | |
ThisPayload.Add("https://ims-na1.adobelogin.com/s/ent_user_sdk", True) | |
Dim ThisJwtToken As String = String.Empty | |
Try | |
Dim ThisPfx As X509Certificate2 = New X509Certificate2(ThisPfxFilePath, CertPfxSecret, X509KeyStorageFlags.MachineKeySet Or X509KeyStorageFlags.PersistKeySet Or X509KeyStorageFlags.Exportable) | |
ThisJwtToken = Jose.JWT.Encode(ThisPayload, ThisPfx.GetRSAPrivateKey(), JwsAlgorithm.RS256) | |
RetVal.Item("message") = "Succesfull call to Adobe token service" | |
Catch ex As Exception | |
RetVal.Item("message") = ex.Message | |
RetVal.Item("error") = True | |
End Try | |
If CBool(RetVal.Item("error")) Then | |
' Flow through, an error was encountered | |
Else | |
Dim ThisRestClient = New RestSharp.RestClient("https://ims-na1.adobelogin.com/ims/exchange/jwt/") | |
Dim ThisRestRequest = New RestSharp.RestRequest(Method.POST) | |
ThisRestRequest.AddHeader("cache-control", "no-cache") | |
ThisRestRequest.AddHeader("content-type", "multipart/form-data; boundary=----boundary") | |
' Code is from elsewhere, it's messy but it works | |
ThisRestRequest.AddParameter("multipart/form-data; boundary=----boundary", "------boundary" & vbCrLf & "content-disposition: form-data; name=""client_id""" & vbCrLf & vbCrLf & ThisClientKey & vbCrLf & "------boundary" & vbCrLf & "content-disposition: form-data; name=""client_secret""" & vbCrLf & vbCrLf & ThisSecret & vbCrLf & "------boundary" & vbCrLf & "content-disposition: form-data; name=""jwt_token""" & vbCrLf & vbCrLf & ThisJwtToken & vbCrLf & "------boundary--", ParameterType.RequestBody) | |
Dim ThisRestResponse As IRestResponse = Nothing | |
Try | |
ThisRestResponse = ThisRestClient.Execute(ThisRestRequest) | |
Dim ThisDersializer As System.Web.Script.Serialization.JavaScriptSerializer = New System.Web.Script.Serialization.JavaScriptSerializer | |
For Each KV As KeyValuePair(Of String, Object) In CType(ThisDersializer.DeserializeObject(ThisRestResponse.Content), Dictionary(Of String, Object)) | |
If RetVal.ContainsKey(KV.Key) Then | |
RetVal.Item(KV.Key) = KV.Value | |
Else | |
RetVal.Add(KV.Key, KV.Value) | |
End If | |
Next | |
Catch ex As Exception | |
RetVal.Item("error") = True | |
RetVal.Item("message") = ex.Message | |
End Try | |
End If | |
Return RetVal | |
End Function |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment