Created
August 29, 2025 07:12
-
-
Save yiskang/3fd2fdfd753844f8fa12293d67cc5492 to your computer and use it in GitHub Desktop.
Demo how to exchange ASP 3LO access token using APS SSA
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
| <Project Sdk="Microsoft.NET.Sdk"> | |
| <PropertyGroup> | |
| <OutputType>Exe</OutputType> | |
| <RootNamespace>ApsSsaVbConsole</RootNamespace> | |
| <TargetFramework>net8.0</TargetFramework> | |
| </PropertyGroup> | |
| <ItemGroup> | |
| <PackageReference Include="Newtonsoft.Json" Version="13.0.3" /> | |
| <PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="8.14.0" /> | |
| </ItemGroup> | |
| </Project> |
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
| Imports System | |
| Imports System.Collections.Generic | |
| Imports System.IdentityModel.Tokens.Jwt | |
| Imports System.Net.Http | |
| Imports System.Net.Http.Headers | |
| Imports System.Security.Claims | |
| Imports System.Security.Cryptography | |
| Imports System.Text | |
| Imports System.Threading.Tasks | |
| Imports Microsoft.IdentityModel.Tokens | |
| Imports System.Net.Http.Json | |
| Imports Newtonsoft.Json.Linq | |
| Module Program | |
| Sub Main(args As String()) | |
| Dim APS_CLIENT_ID As String = "YOUR_CLIENT_ID" | |
| Dim APS_CLIENT_SECRET As String = "YOUR_CLIENT_SECRET" | |
| Dim SERVICE_ACCOUNT_ID As String = "YOUR_SSA_ACOUNT_ID" | |
| Dim KEY_ID As String = "YOUR_SSA_KEY_ID" | |
| Dim PRIVATE_KEY As String = "-----BEGIN RSA PRIVATE KEY----- | |
| YOUR_PRIVATE_KEY | |
| -----END RSA PRIVATE KEY-----" | |
| Dim SCOPE As String() = {"data:read", "data:write"} | |
| Dim jwtAssertion As String = GenerateJwtAssertion(KEY_ID, PRIVATE_KEY, APS_CLIENT_ID, SERVICE_ACCOUNT_ID, SCOPE) | |
| Dim tokenResponse As String = GetAccessToken(jwtAssertion, APS_CLIENT_ID, APS_CLIENT_SECRET, SCOPE).Result | |
| Console.WriteLine("Access Token Response:") | |
| Console.WriteLine(tokenResponse) | |
| End Sub | |
| Function GenerateJwtAssertion(keyId As String, privateKeyPem As String, clientId As String, ssa_id As String, scope As String()) As String | |
| ' Create RSA from the PEM-formatted private key | |
| Using rsa As RSA = RSA.Create() | |
| privateKeyPem = privateKeyPem.Replace(vbCrLf, vbLf) | |
| rsa.ImportFromPem(privateKeyPem.ToCharArray()) | |
| Dim securityKey As New RsaSecurityKey(rsa) With { | |
| .keyId = keyId | |
| } | |
| Dim signingCredentials As New SigningCredentials(securityKey, SecurityAlgorithms.RsaSha256) | |
| ' Build JWT claims | |
| Dim claims As New List(Of Claim) From { | |
| New Claim("iss", clientId), | |
| New Claim("sub", ssa_id), | |
| New Claim("aud", "https://developer.api.autodesk.com/authentication/v2/token") | |
| } | |
| For Each scopeStr As String In scope | |
| claims.Add(New Claim("scope", scopeStr)) | |
| Next | |
| ' Create the token with a 5-minute expiration | |
| Dim jwtToken As New JwtSecurityToken( | |
| claims:=claims, | |
| expires:=DateTime.UtcNow.AddSeconds(300), | |
| signingCredentials:=signingCredentials | |
| ) | |
| Dim tokenHandler As New JwtSecurityTokenHandler() | |
| Return tokenHandler.WriteToken(jwtToken) | |
| End Using | |
| End Function | |
| Async Function GetAccessToken(jwtAssertion As String, clientId As String, clientSecret As String, scope As String()) As Task(Of String) | |
| Using client As New HttpClient() | |
| Dim request As New HttpRequestMessage(HttpMethod.Post, "https://developer.api.autodesk.com/authentication/v2/token") | |
| request.Headers.Accept.Add(New MediaTypeWithQualityHeaderValue("application/json")) | |
| request.Content = New FormUrlEncodedContent(New Dictionary(Of String, String) From { | |
| {"grant_type", "urn:ietf:params:oauth:grant-type:jwt-bearer"}, | |
| {"assertion", jwtAssertion}, | |
| {"scope", String.Join(" ", scope)} | |
| }) | |
| ' Encode client ID and secret for basic auth | |
| Dim authenticationString As String = $"{clientId}:{clientSecret}" | |
| Dim base64EncodedAuthenticationString As String = Convert.ToBase64String(Encoding.ASCII.GetBytes(authenticationString)) | |
| request.Headers.Authorization = New AuthenticationHeaderValue("Basic", base64EncodedAuthenticationString) | |
| Try | |
| Dim response = Await client.SendAsync(request) | |
| Dim msg As String = Await response.Content.ReadAsStringAsync() | |
| Console.WriteLine(msg) | |
| response.EnsureSuccessStatusCode() | |
| Return msg | |
| Catch ex As Exception | |
| Throw New InvalidOperationException() | |
| End Try | |
| End Using | |
| End Function | |
| End Module |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment