Fetching Access token using Auth token from service in C# - c#

I am new to the topic of Oauth and encryption. I need to write a utility where I have authtoken with me and I need to get access token after making a call to the service url say xyzcorp.com. I already have auth token with me I need to use post method to make service call to the url which in turn returns access token. I couldn't find any code snippet which shows how this is done. As I already said I am a newbie into this area, don't have any clue about the implementation in c#. It should be noted that I only have auth token with me.

What C# library are you using? I used Thinktecture.IdentityModel:
https://github.com/thinktecture/Thinktecture.IdentityModel
Here's an example from my OAuth2 Test Client, using IdentityModel:
private static async Task<TokenResponse> SendTokenRequest(string authCode, string redirectUri)
{
var tokenclient = new OAuth2Client(
new Uri(Constant.TokenEndpoint),
Constant.CodeClientId,
Constant.CodeClientSecret);
return await tokenclient.RequestAuthorizationCodeAsync(authCode, redirectUri);
}

Related

C# Smartsheet SDK - oauth authentication failing to get token

I am trying to do some basic sheet updates via the c# sdk. For apps/integrations with smartsheet there are 2 options: "Apps" and "API Access". When I use a static API Access token I can get everything to work fine through my user, however I am trying to do oauth through the integrated apps which contains a client id/client secret. On the oauth.ObtainNewToken step I get the following error:
Smartsheet.Api.OAuth.OAuthTokenException: 'Token request failed with http error code: Forbidden'
Trying to figure if I'm missing a step or doing something wrong. I am using the client secret/client id in an ssis package oauth connector that apparently has a static token which works fine, so I know the client id/secret aren't wrong. Any advice would be appreciated, thank you. Code below:
public static Token getAuthToken(string clientId, string appSecret, string authorizationURL, string redirectURL, string tokenURL)
{
/*
Authorization url - https://app.smartsheet.com/b/authorize
Token URL - https://api.smartsheet.com/2.0/token
*/
OAuthFlow oauth = new OAuthFlowBuilder()
.SetTokenURL(tokenURL)
.SetAuthorizationURL(authorizationURL)
.SetClientId(clientId)
.SetClientSecret(appSecret)
.SetRedirectURL(redirectURL)
.Build();
string url = oauth.NewAuthorizationURL(new List<AccessScope> { AccessScope.READ_SHEETS, AccessScope.WRITE_SHEETS, AccessScope.SHARE_SHEETS, AccessScope.READ_CONTACTS, AccessScope.READ_SIGHTS, AccessScope.SHARE_SIGHTS},"/");
AuthorizationResult authResult = oauth.ExtractAuthorizationResult(url);
Token token = oauth.ObtainNewToken(authResult);
return token;
}

Best practices for managing Web API JWT token in another Web API

My Project:
Web API project - ASP .NET Framework 4.8
Problem?
The code flow is as follows:
1.) The API is called -> it must call another API -> 2.) Get JWT authentication token -> 3.) Calls the desired method.
The problem is if my API is called 100 times, I will make 100 calls for the GetJwtToken() method and another 100 for the desired method itself, which seems like an overhead on the auth server. The token itself has a lifespan of 2 hours.
Are there any documented best practices on how to manage a Web API JWT token in another Web API?
What have I tried?
I've tried the following solutions and I'm still not sure whether they could be considered good practices.
One static class with two static properties Token and ValidTo and one static method GetJwtToken() that updates those properties. Before each call to the desired external API method, we check the ValidTo property and update the Token value if it has expired, via the static method.
In our service, we have one static private field Token.The method that calls the external API method is surrounded by a try catch blocks. The Catch(WebException ex) expects an Unauthorized exception if the token has expired. I check for HTTP Status Code 401 - Unauthorized.
if (response.StatusCode == HttpStatusCode.Unauthorized)
In case we go into that if clause we update the Token property by calling the GetJwtToken() method inside the catch block and then calling recursively the method again. In this way, we update the token only when it has expired and an unauthorized exception was thrown.
Another idea that I got, but didn't test isActionFilterAttribute with overridden OnActionExecuting(HttpActionContext actionContext) method. Before we go into the Web API controller the action attribute has already checked whether we have Token and if it has expired. The problem here was I am not sure where to save the Token property. Possibly as a static value in another class.
Are there any other ways to manage a JWT Token of a Web API inside another Web API and what is considered best practices?
Some code snippets, pseudo-code, or articles would be appreciated.
Edit1:
I've read this question, but it doesn't help me, since it's about how to manage the token on the front end part. The project here is Web API it's all on the server-side.
Edit2:
Edited some sentences here and there so it's more readable.
Edit3:
Added one more option that I thought about.
I'd handle this in some kind of BaseApiService
public class BaseApiService
{
private readonly IHttpClientFactory httpClientFactory;
private readonly ITokenHandler tokenHandler;
public BaseApiService(IHttpClientFactory httpClientFactory, ITokenHandler tokenHandler)
{
this.httpClientFactory = httpClientFactory;
this.tokenHandler = tokenHandler;
}
protected async Task<HttpResponseMessage> RequestAsync(HttpRequestMessage requestMessage)
{
var httpClient = httpClientFactory.CreateClient();
requestMessage.Headers.Authorization = new AuthenticationHeaderValue("Bearer", tokenHandler.Token);
var response = await httpClient.SendAsync(requestMessage);
if (!response.IsSuccessStatusCode)
{
if (response.StatusCode == HttpStatusCode.Unauthorized)
{
var token = await tokenHandler.UpdateTokenAsync();
requestMessage.Headers.Authorization = new AuthenticationHeaderValue("Bearer", token);
return await RequestAsync(requestMessage);
}
}
return response;
}
}
Which would be responsible for making request, response serialization (notice I've used string responses for simplicity sake) and handling token for each request. Also you might want to consider handling errors and also handle infinite loops because it's currently calling self (e.g. on second call if it's unauthorized again, exit with error).
Token handler would be defined as singleton in DI and this is implementation
public interface ITokenHandler
{
string Token { get; }
Task<string> UpdateTokenAsync();
}
public class TokenHandler : ITokenHandler
{
private readonly IHttpClientFactory httpClientFactory;
public string Token { get; private set; }
public TokenHandler(IHttpClientFactory httpClientFactory)
{
this.httpClientFactory = httpClientFactory;
}
public async Task<string> UpdateTokenAsync()
{
var httpClient = httpClientFactory.CreateClient();
var result = await httpClient.PostAsync("/external-api/token", new FormUrlEncodedContent(new []
{
new KeyValuePair<string, string>("username", "external-admin"),
new KeyValuePair<string, string>("password", "external-password"),
}));
// or handle it however you want
var token = result.IsSuccessStatusCode
? await result.Content.ReadAsStringAsync()
: null;
if (!String.IsNullOrEmpty(token))
{
Token = token;
}
return Token;
}
}
And this is how you'd consume your BaseApiService
public class TodoService : BaseApiService
{
public TodoService(IHttpClientFactory httpClientFactory, ITokenHandler tokenHandler)
: base(httpClientFactory, tokenHandler)
{
}
public async Task<string> GetTodoAsync(int id)
{
var response = await RequestAsync(new HttpRequestMessage(HttpMethod.Get, $"/todo/{id}"));
return await response.Content.ReadAsStringAsync();
}
}
I don't think you need to add any ValidTo logic, but just rely on your Unauthorized response from 3rd party API, because you'll just complicate your code and you'll have to handle Unauthorized responses anyway.
Only thing is that you might lock getting/setting of token from TokenHandler, but this is just a basic example to show an idea how I'd implement it.
I will expand my comments to answer because of the characters limit.
First, re-consider / re-examine why do you need to call the auth server for every API call? Do you have a data store of some kind like a database, a cache (in memory or remote), a Azure blob storage or a shared folder? If you have, you could consider persist your access tokens to your choice of data store.
Now, let's deal with token expiration time. Depends on how the external API grants the access tokens (I assume it is OAuth2 here), you usually could access the expiration time of a token, for example using expires_in in the response. The expires_in is equal to seconds since the unix epoch, so you should know when the token will expire. You could then save the token granted to your data store along with their expiration time and refresh token. When you use cache, you could set the cache entry to expire minutes before the token in it expires.
When you get next API call, check if you have a "valid" token from your data store. If no, call to get new JWT token and persist it using above method. Otherwise, try make API call with the token from your data store. If you have a background service, like a WebJob or Hangfire, you could periodically validate all tokens against the token validation endpoint (if your external API provides one) and refresh them when needed.
You should always handle unauthorized responses. Tokens can be revoked before they expire. In the case of unauthorized response received at your end, you could try re-authenticate with the external API and refresh the token kept in your data store. If the token generation needs to get user involved, you could return 401 to your client.
Lastly, you will also need to consider security. When you persist the tokens, even to your own data store, you need to encrypt them. This is for ASP.NET Core, but still worth reading it and do something similar in your API.
Perhaps consider you API to save the AuthToken (stateful).
I'm confused though of your current flow, usually you'll have an AuthApi that has the function to provide AuthorizationTokens.
Once the caller has the AuthToken it should save it; for front-end as you know, local storage, session storage, and cookies are considered, for backend or an API you could consider a stateful API which will save the Token in a global state, so it can append it to every request without going back-and-forth with your AuthApi (It will do a trip when the token expires though, etc.).

How to get the oauth refresh token?

I have a web app which utlizes Oauth and is unable to reuse the authToken due to the error below.
{"AADSTS70002: Error validating credentials. AADSTS54005: OAuth2 Authorization
code was already redeemed, please retry with a new valid code or use an
existing refresh token.\r\nTrace ID: 30c342a7-f16a-4a05-a4a8-
c7ee2c722300\r\nCorrelation ID: 3a5c99d1-ca1c-4cd7-bd36-
cce721bf05b6\r\nTimestamp: 2018-11-21 00:26:18Z"}
I'm told this is a know issue/update here and here.
...okay, fine so now I'm trying to get the refresh token so I can regenerate my access token but I'm having trouble getting something to work.
I have tried the ones below:
https://learn.microsoft.com/en-us/bingads/shopping-content/code-example-authentication-oauth - this one does not seem to work and throws an exception when I try to get the accesstoken or refresh token. stating that one or more errors have occured.
https://auth0.com/docs/api/authentication#authorization-code-pkce- - but does not return the refresh token. Could this be because I don't have the code_verifier? If so, how would I get that?
Authorization Code (PKCE) Image
Below is a code sample which I am using - problem here is that I can only use this once and once It has been redemed I cannot retrive it silently as it no longer exists in the cache.
ClientCredential clientcred = new ClientCredential(Constants.ClientId, Constants.AppKey);
TokenCache TC = new TokenCache();
AuthenticationContext AC = new AuthenticationContext(Constants.Authority, TC);
//Set token from authentication result
AuthenticationResult authenticationResult = await AC.AcquireTokenByAuthorizationCodeAsync(
Constants.Code,
new Uri(Constants.postLogoutRedirectUri + "Index"), clientcred);
return authenticationResult.AccessToken;
You need to call OAuth2 authorize endpoint with offline_access scope to get refresh token.
You should call AcquireTokenByAuthorizationCodeAsync only once when you receive authorization code and should not use the result. azure ad sample
You need to call AcquireTokenSilently when you want to get access token. azure ad sample
This azure ad sample use a TokenCache implementation by user id.
Authorize request
Token request
Good luck!

Identity Server Get new token or populate claim without logout

implicit grant flow:
Is there a way I can get new bearer token (and new refresh_token?) for specific scenario.
So I have some actions on app where its going to call api on the server which will need to populate new claims (and new bearer token as a result).
My question is how (or where) do I do this without user logging out?
Thanks,
EDIT:
As it turns out refresh tokens in implict flow is a bad idea.
Prob. another way to put the same question ...
In Identity Server 4 is there any where (a delegate, method call etc.) which can be used to add new claims to the existing token? So for e.g. If I have an endpoint https://myauthserver/changemypincode and from that endpoint I can call this (a delegate, method call etc.) to add new claims to the token (it could create new token as result but thats fine) and return to client?
I know this is an old question, but you can solve this by using the IdentityServerTools to generate a new token.
private async Task<string> CreatePaymentsTokenAsync()
{
var tokenLifeTime = 3600;
var scopes = new[] { CoinbaseAuthConsts.PaymentScope };
// Use in-built Identity Server tools to issue JWT
var token = await _identityServerTools.IssueClientJwtAsync(CoinbaseAuthConsts.AuthorityClientId,
tokenLifeTime, scopes, new[] { "YourApiName" });
return token;
}

How to call GData services with an OAuth access token?

I have an OAuth access token that I got from:
var state = new AuthorizationState(new[] { "http://www.google.com/m8/feeds/" })
{
Callback = new Uri(NativeApplicationClient.OutOfBandCallbackUrl)
};
// Redirect to:
var authUri = arg.RequestUserAuthorization(state)
...
var authState = arg.ProcessUserAuthorization(authCode, state);
After that, how do I pass the authState.AccessToken to the services from the GData API?
All the examples I find pass an OAuth2Authenticator<> to the constructor of the service, such as:
var auth = new OAuth2Authenticator<NativeApplicationClient>(...);
var service = new PlusService(auth);
I am trying to use the ContactsService but the latest version (2.2.0.0) does not seem to have this constructor - the only constructor takes an application name.
I have tried setting the access token with ContactsService.SetAuthenticationToken() but the request header is incorrectly set, it will look like this:
Authorization: GoogleLogin auth=<access token>
Instead of:
Authorization: Bearer <access token>
There does not seem to be any method to manipulate the headers either.
We ran into the same problem. Instead of using SetAuthenticationToken(), you should assign the RequestFactory with an OAuth2RequestFactory as suggested by the examples provided on the GData API page.
Now this seems somewhat counter-intuitive if you already are managing OAuth tokens outside of the GData API. It turns out that you do not need to actually provide the clientId, clientSecret, etc to the request factory. The only field that matters is the OAuth access token, if that is a valid access token.
At least for us, we found that with this approach, the GData API correctly specifies the Authorization Http header, and the API calls are successful.

Categories

Resources