- Mark Topic as New
- Mark Topic as Read
- Float this Topic for Current User
- Bookmark
- Subscribe to Topic
- Printer Friendly Page
- Mark as New
- Bookmark
- Subscribe
- Mute
- Permalink
- Report Inappropriate Content
Hello @Nelson_Lin ,
I'm trying to implement a solution without the Key Vault but failed multiple times.
So my question: Is it possible to write an application without Key Vault / how can I replace all the calls to the Key Vault?
Thank you
Klaus
- Mark as New
- Bookmark
- Subscribe
- Mute
- Permalink
- Report Inappropriate Content
Hi @KlausPruenster,
It is possible to develop a solution that does not require Azure Key Vault. However, I would like to mention that is highly recommended that you leverage a solution that provides similar protection that you get with Azure Key Vault. It is not recommended that you store the application secret and refresh token values in the configuration files. With respect to the Cloud Solution Provider sample the secret was stored in the configuration because that is a sample, and we wanted to make sure the work required to get started with the sample was minmized.
When you are working with the samples, you will want to look at LoginToPartnerCenter function and replace the respective calls to Azure Key Vault with whatever is appropriate for your solution.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Permalink
- Report Inappropriate Content
Hi @idwilliams,
what I tried so far is this:
public static async Task<Tuple<string, DateTimeOffset>> LoginToPartnerCenter(string tenantId) { KeyVaultProvider provider = new KeyVaultProvider(); //var refreshToken = await provider.GetSecretAsync(tenantId); var refreshToken = await AuthorizationUtilities.GetADAppToken("https://login.microsoftonline.com/" + tenantId, "https://api.partnercenter.microsoft.com", CSPApplicationId, CSPApplicationSecret); var token = await AuthorizationUtilities.GetAADTokenFromRefreshToken("https://login.microsoftonline.com/" + tenantId, "https://api.partnercenter.microsoft.com", CSPApplicationId, CSPApplicationSecret, refreshToken["access_token"].ToString()); return new Tuple<string, DateTimeOffset>(token["access_token"].ToString(), DateTimeOffset.UtcNow + TimeSpan.FromTicks(long.Parse(token["expires_on"].ToString()))); }
The first request works, I get a token in the variable refreshToken.
Executing the AuthorizationUtilities.GetAADTokenFromRefreshToken function i get this result:
{"error":"invalid_grant","error_description":"AADSTS9002313: Invalid request. Request is malformed or invalid.\r\nTrace ID: ..............\r\nCorrelation ID: ...............\r\nTimestamp: 2019-02-26 16:38:16Z","error_codes":[9002313],"timestamp":"2019-02-26 16:38:16Z","trace_id":"..........","correlation_id":"..........."}
Do you have any idea where I'm making the mistake here?
- Mark as New
- Bookmark
- Subscribe
- Mute
- Permalink
- Report Inappropriate Content
Hi @KlausPruenster,
The GetADAppToken method perform app only authentication, and it does not return a refresh token. So, you are getting the invalid grant error because you are using an access token instead of a refresh token. With the samples we have provide the refresh token value is obtained using the partner consent sample. It is a web application that leverages Azure Active Directory for authentication. Once you successfully authenticate it requests an access token, the response for that request will include the refresh token value. That value is then stored in Azure Key Vault, and it will be used for future operations to request access tokens.
You can simplify this process by using the PowerShell to obtain the refresh token. For more information on how to accomplish this see Partner Center PowerShell | Secure App Model. You will want to capture the refresh token, store it somewhere secure, and then modify your code to look something like the following
public static async Task<Tuple<string, DateTimeOffset>> LoginToPartnerCenter(string tenantId) { // Do not hard code the refresh token value. // It should be obtained from a secure location. string refreshToken = "REFRESH-TOKEN-VALUE-HERE"; Newtonsoft.Json.Linq.JObject token = await AuthorizationUtilities.GetAADTokenFromRefreshToken( "https://login.microsoftonline.com/" + tenantId, "https://api.partnercenter.microsoft.com", CSPApplicationId, CSPApplicationSecret, refreshToken); return new Tuple<string, DateTimeOffset>(token["access_token"].ToString(), DateTimeOffset.UtcNow + TimeSpan.FromTicks(long.Parse(token["expires_on"].ToString()))); }
- Mark as New
- Bookmark
- Subscribe
- Mute
- Permalink
- Report Inappropriate Content
Hello @idwilliams ,
thank you so much for your help. Somehow I missed the fact of the second solution where the refresh token is collected hence I didn't understand where this token is coming from
But there is one more question left: I'm working on a service to service program, and the solution you implemented requires a UI to get the refresh token. Is there a way to request a refresh token without any user interaction?
Thank you
Klaus
- Mark as New
- Bookmark
- Subscribe
- Mute
- Permalink
- Report Inappropriate Content
Hi @KlausPruenster,
You will not be able to automate the entire process because of the requirement for multi-factor authentication. That requirement will require an interactive component such as providing an access code from an authenticator application. With this said the generation of the refresh token could be a one time operation depending on how it is generated.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Permalink
- Report Inappropriate Content
Yes, it's possible since from what I can tell, all you are storing in the Key Vault is a Key-Value pair. I was able to store those values in the web.config file, and it seemed to work fine for me.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Permalink
- Report Inappropriate Content
Hi @Ray,
okay, I'm still having some issues do you think you could give me your sample code?
- Mark as New
- Bookmark
- Subscribe
- Mute
- Permalink
- Report Inappropriate Content
Hi @KlausPruenster,
I hope Isaiah Williams answered most of your questions. Do you still require sample code? I used PowerShell to generate the refresh token as described in the link that Isaiah posted as I could not generate it automatically through code as he mentioned. I then modified my REST call to obtain the access token to make my other calls. I would also concur with Isaiah that you should store the refresh token in Azure Key Vault. I was able to make my program work with both (i.e. Azure Key Vault and just storing it in a configuration file), so my previous post was just to say it's possible but probably not best practice.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Permalink
- Report Inappropriate Content
Hi @Ray,
yes, @idwilliams answered all my questions so I won't require your example code.
Thank you both! You helped me a lot!
