Skip to content

Instantly share code, notes, and snippets.

@MorningZ
Last active January 8, 2020 18:03
Show Gist options
  • Save MorningZ/df3775548b61fd6a5124a72b85999389 to your computer and use it in GitHub Desktop.
Save MorningZ/df3775548b61fd6a5124a72b85999389 to your computer and use it in GitHub Desktop.
Create Adobe.IO token via VB.NET
' 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