Skip to content

Instantly share code, notes, and snippets.

@alexeyzimarev
Last active September 14, 2023 12:40
Show Gist options
  • Save alexeyzimarev/62d77bb25d7aa5bb4b9685461f8aabdd to your computer and use it in GitHub Desktop.
Save alexeyzimarev/62d77bb25d7aa5bb4b9685461f8aabdd to your computer and use it in GitHub Desktop.
using System.Text.Json.Serialization;
using RestSharp.Authenticators;
namespace RestSharp.Tests.External.Twitter;
public interface ITwitterClient {
Task<TwitterUser> GetUser(string user);
}
public class TwitterClient : ITwitterClient, IDisposable {
readonly RestClient _client;
public TwitterClient(string apiKey, string apiKeySecret) {
var options = new RestClientOptions("https://api.twitter.com/2");
_client = new RestClient(options) {
Authenticator = new TwitterAuthenticator("https://api.twitter.com", apiKey, apiKeySecret)
};
}
public async Task<TwitterUser> GetUser(string user) {
var response = await _client.GetJsonAsync<TwitterSingleObject<TwitterUser>>(
"users/by/username/{user}",
new { user }
);
return response!.Data;
}
record TwitterSingleObject<T>(T Data);
public void Dispose() {
_client?.Dispose();
GC.SuppressFinalize(this);
}
}
public class TwitterAuthenticator : AuthenticatorBase {
readonly string _baseUrl;
readonly string _clientId;
readonly string _clientSecret;
public TwitterAuthenticator(string baseUrl, string clientId, string clientSecret) : base("") {
_baseUrl = baseUrl;
_clientId = clientId;
_clientSecret = clientSecret;
}
protected override async ValueTask<Parameter> GetAuthenticationParameter(string accessToken) {
var token = string.IsNullOrEmpty(Token) ? await GetToken() : Token;
return new HeaderParameter(KnownHeaders.Authorization, token);
}
async Task<string> GetToken() {
var options = new RestClientOptions(_baseUrl);
using var client = new RestClient(options) {
Authenticator = new HttpBasicAuthenticator(_clientId, _clientSecret),
};
var request = new RestRequest("oauth2/token")
.AddParameter("grant_type", "client_credentials");
var response = await client.PostAsync<TokenResponse>(request);
return $"{response!.TokenType} {response!.AccessToken}";
}
record TokenResponse {
[JsonPropertyName("token_type")]
public string TokenType { get; init; }
[JsonPropertyName("access_token")]
public string AccessToken { get; init; }
}
}
public record TwitterUser(string Id, string Name, string Username);
@alexeyzimarev
Copy link
Author

@miai-demant feel free to provide a better example. I never claimed that it should be considered as production code. It is, as described, an example.

@alexeyzimarev
Copy link
Author

@lcordy

means every client request will get a new token

Adding one line after line 49 solves it, I am not sure why it's such a big issue

        Token = token;

@vanderlei-dev
Copy link

vanderlei-dev commented Jan 31, 2023

I created a updated version that handle expiration date, for anyway interested is over here:
https://gist.github.com/vanderlei-dev/665d7cd7c90aee0bf3e38e83dad5c7d2

Thanks @alexeyzimarev for the base example.

@alexeyzimarev
Copy link
Author

Cool! Thanks @vanderlei-dev

@keyse
Copy link

keyse commented May 9, 2023

v107 documentation is not correct.
_client = new RestClient(options)
{
Authenticator = new TwitterAuthenticator("https://api.twitter.com", apiKey, apiKeySecret)
};

The above code will NOT compile because Authenticator is getter and can not be set.

@alexeyzimarev
Copy link
Author

I appreciate the report, but it would've been better to open an issue in the RestSharp repository rather than commenting on my old gist.

@PedroNetto404
Copy link

PedroNetto404 commented Jul 17, 2023

@keyse just inform during the creation of the RestClientOptions instance:

 async Task<TokenResponse> GetToken() 
{
        //here
       var options = new RestClientOptions(_baseUrl){ Authenticator = new HttpBasicAuthenticator(_clientId, _clientSecret) };
        //not here
        using var client = new RestClient(options) { // Authenticator = new HttpBasicAuthenticator(_clientId, _clientSecret) };

        var request = new RestRequest("oauth2/token") .AddParameter("grant_type", "client_credentials");

        return await client.PostAsync<TokenResponse>(request); 
} 

@alexeyzimarev thanks for your example, it was a great help!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment