Skip to content

Commit fa38a6b

Browse files
committed
#938 AuthenticationRequestToken -> AuthenticationRequest
AuthenticationRequestProvider -> AuthenticationRequestStore AuthenticationRequestStore is now an element for the developers to take care of. Tweetinvi no longer relies on it.
1 parent 7a413a9 commit fa38a6b

28 files changed

+214
-343
lines changed

CHANGELOG.md

+10-9
Original file line numberDiff line numberDiff line change
@@ -40,13 +40,12 @@ As a result, changing a `TwitterClient` credentials will only be possible by cre
4040

4141
## Authentication Flow
4242

43-
`IAuthenticationTokenProvider` is a new interface that let developers customize how Tweetinvi retrieves the AuthenticationToken.
44-
* `CallbackTokenIdParameterName` query parameter added to the callback url.
45-
* `ExtractTokenIdFromCallbackUrl` method extracting a token from a callback url.
46-
* `GenerateAuthTokenId` generates an identifier that will be used by `GetAuthenticationTokenFromId`
47-
* `GetAuthenticationTokenFromId` retrieves an AuthenticationToken from its unique identifier
48-
* `AddAuthenticationToken` defines how to add a token into your store
49-
* `RemoveAuthenticationToken` defines how to remove a token from your store.
43+
`IAuthenticationRequestStore` is a new interface that guides developers through the authentication flow of redirection urls. A default in-memory solution is provided but developers are free to implement their own.
44+
* `AppendAuthenticationRequestIdToCallbackUrl` append an authenticationRequestId to a url
45+
* `ExtractAuthenticationRequestIdFromCallbackUrl` logic to extract an authenticationRequestId from a callback url
46+
* `GetAuthenticationRequestFromId` returns the AuthenticationRequest from its identifier
47+
* `AddAuthenticationToken` stores the AuthenticationRequest information
48+
* `RemoveAuthenticationToken` removes an AuthenticationRequest from the store
5049

5150
A default implementation `new AuthenticationTokenProvider` is an implementation that allow you to make the `AuthenticationToken` accessible from an in-memory store.
5251

@@ -67,14 +66,16 @@ A default implementation `new AuthenticationTokenProvider` is an implementation
6766

6867
**`AuthFlow.InitAuthentication`** was moved to `TwitterClient.Auth.RequestAuthenticationUrl`
6968

69+
`RequestAuthenticationUrl` returns an `AuthenticationRequest` which contains the url to redirected the user and authorization information to proceed with the request of credentials.
70+
7071
``` c#
7172
// Tweetinvi 4.0
7273
Auth.SetCredentials(new TwitterCredentials("consumer_key", "consumer_secret"));
73-
var authenticationContext = AuthFlow.InitAuthentication(applicationCredentials);
74+
var authenticationRequest = AuthFlow.InitAuthentication(applicationCredentials);
7475

7576
// Tweetinvi 5.0
7677
var appClient = new TwitterClient(new TwitterCredentials("consumer_key", "consumer_secret"));
77-
var authenticationContext = await authenticationClient.Auth.RequestAuthenticationUrl();
78+
var authenticationRequest = await authenticationClient.Auth.RequestAuthenticationUrl();
7879
```
7980

8081
**`AuthFlow.CreateCredentialsFromVerifierCode` moved to `TwitterClient.Auth.RequestCredentials`**

Examples/Examplinvi.ASP.NET.Core/Controllers/HomeController.cs

+15-6
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
using System.Diagnostics;
1+
using System;
2+
using System.Diagnostics;
23
using System.Threading.Tasks;
34
using Examplinvi.ASP.NET.Core.Models;
45
using Microsoft.AspNetCore.Mvc;
@@ -13,7 +14,7 @@ public class HomeController : Controller
1314
/// <summary>
1415
/// NOTE PLEASE CHANGE THE IMPLEMENTATION OF IAuthenticationTokenProvider to match your needs
1516
/// </summary>
16-
private static readonly IAuthenticationTokenProvider _myAuthProvider = new AuthenticationTokenProvider();
17+
private static readonly IAuthenticationRequestStore _myAuthRequestStore = new AuthenticationRequestStore();
1718

1819
public IActionResult Index()
1920
{
@@ -34,17 +35,25 @@ private static ITwitterClient GetAppClient()
3435
public async Task<ActionResult> TwitterAuth()
3536
{
3637
var appClient = GetAppClient();
37-
var redirectURL = "https://" + Request.Host.Value + "/Home/ValidateTwitterAuth";
38-
var authenticationContext = await appClient.Auth.RequestAuthenticationUrl(redirectURL, _myAuthProvider);
3938

40-
return new RedirectResult(authenticationContext.AuthorizationURL);
39+
var authRequestId = Guid.NewGuid().ToString();
40+
var redirectURL = _myAuthRequestStore.AppendAuthenticationRequestIdToCallbackUrl($"https://{Request.Host.Value}/Home/ValidateTwitterAuth", authRequestId);
41+
var authenticationRequestToken = await appClient.Auth.RequestAuthenticationUrl(redirectURL);
42+
await _myAuthRequestStore.AddAuthenticationToken(authRequestId, authenticationRequestToken);
43+
44+
return new RedirectResult(authenticationRequestToken.AuthorizationURL);
4145
}
4246

4347
public async Task<ActionResult> ValidateTwitterAuth()
4448
{
4549
var appClient = GetAppClient();
4650

47-
var requestParameters = await RequestCredentialsParameters.FromCallbackUrl(Request.QueryString.Value, _myAuthProvider);
51+
// RequestCredentialsParameters.FromCallbackUrl does 3 things:
52+
// * Extract the id from the callback
53+
// * Get the AuthenticationRequest from the store
54+
// * Remove the request from the store as it will no longer need it
55+
// This logic can be implemented manually if you wish change the behaviour
56+
var requestParameters = await RequestCredentialsParameters.FromCallbackUrl(Request.QueryString.Value, _myAuthRequestStore);
4857
var userCreds = await appClient.Auth.RequestCredentials(requestParameters);
4958

5059
var userClient = new TwitterClient(userCreds);

Tests/xUnitinvi/ClientActions/AuthClient/AuthControllerTests.cs

+5-39
Original file line numberDiff line numberDiff line change
@@ -72,10 +72,7 @@ public async Task StartAuthProcess_WithRedirectUrl_ReturnsFromRequestExecutor()
7272
var controller = CreateAuthController();
7373
var request = A.Fake<ITwitterRequest>();
7474
var expectedResult = A.Fake<ITwitterResult>();
75-
var parameters = new RequestUrlAuthUrlParameters("my_url")
76-
{
77-
RequestId = null
78-
};
75+
var parameters = new RequestUrlAuthUrlParameters("my_url");
7976
var response = "oauth_token=MY_TOKEN&oauth_token_secret=MY_SECRET&oauth_callback_confirmed=true";
8077

8178
A.CallTo(() => _fakeAuthQueryExecutor.RequestAuthUrl(A<RequestAuthUrlInternalParameters>.That.Matches(x => x.CallbackUrl == "my_url"), request))
@@ -90,45 +87,17 @@ public async Task StartAuthProcess_WithRedirectUrl_ReturnsFromRequestExecutor()
9087
Assert.Equal("MY_SECRET", result.DataTransferObject.AuthorizationSecret);
9188
}
9289

93-
[Fact]
94-
public async Task StartAuthProcess_WithRedirectUrlAndAuthId_ReturnsFromRequestExecutor()
95-
{
96-
// Arrange
97-
var controller = CreateAuthController();
98-
var request = A.Fake<ITwitterRequest>();
99-
var expectedResult = A.Fake<ITwitterResult>();
100-
var parameters = new RequestUrlAuthUrlParameters("my_url")
101-
{
102-
RequestId = "my_auth_id"
103-
};
104-
var response = "oauth_token=MY_TOKEN&oauth_token_secret=MY_SECRET&oauth_callback_confirmed=true";
105-
106-
A.CallTo(() => _fakeAuthQueryExecutor.RequestAuthUrl(A<RequestAuthUrlInternalParameters>.That.Matches(x => x.CallbackUrl == "my_url?authorization_id=my_auth_id"), request))
107-
.Returns(expectedResult);
108-
A.CallTo(() => expectedResult.Json).Returns(response);
109-
110-
// Act
111-
var result = await controller.RequestAuthUrl(parameters, request);
112-
113-
// Assert
114-
Assert.Equal("MY_TOKEN", result.DataTransferObject.AuthorizationKey);
115-
Assert.Equal("MY_SECRET", result.DataTransferObject.AuthorizationSecret);
116-
}
117-
11890
[Fact]
11991
public async Task StartAuthProcess_WithNonConfirmedCallback_ShouldThrowAsAborted()
12092
{
12193
// Arrange
12294
var controller = CreateAuthController();
12395
var request = A.Fake<ITwitterRequest>();
12496
var expectedResult = A.Fake<ITwitterResult>();
125-
var parameters = new RequestUrlAuthUrlParameters("my_url")
126-
{
127-
RequestId = "my_auth_id"
128-
};
97+
var parameters = new RequestUrlAuthUrlParameters("my_url");
12998
var response = "oauth_token=MY_TOKEN&oauth_token_secret=MY_SECRET&oauth_callback_confirmed=false";
13099

131-
A.CallTo(() => _fakeAuthQueryExecutor.RequestAuthUrl(A<RequestAuthUrlInternalParameters>.That.Matches(x => x.CallbackUrl == "my_url?authorization_id=my_auth_id"), request))
100+
A.CallTo(() => _fakeAuthQueryExecutor.RequestAuthUrl(A<RequestAuthUrlInternalParameters>.That.Matches(x => x.CallbackUrl == "my_url"), request))
132101
.Returns(expectedResult);
133102
A.CallTo(() => expectedResult.Json).Returns(response);
134103

@@ -143,14 +112,11 @@ public async Task StartAuthProcess_WithoutResponse_ShouldThrowAuthException()
143112
var controller = CreateAuthController();
144113
var request = A.Fake<ITwitterRequest>();
145114
var expectedResult = A.Fake<ITwitterResult>();
146-
var parameters = new RequestUrlAuthUrlParameters("my_url")
147-
{
148-
RequestId = "my_auth_id"
149-
};
115+
var parameters = new RequestUrlAuthUrlParameters("my_url");
150116

151117
var response = "";
152118

153-
A.CallTo(() => _fakeAuthQueryExecutor.RequestAuthUrl(A<RequestAuthUrlInternalParameters>.That.Matches(x => x.CallbackUrl == "my_url?authorization_id=my_auth_id"), request))
119+
A.CallTo(() => _fakeAuthQueryExecutor.RequestAuthUrl(A<RequestAuthUrlInternalParameters>.That.Matches(x => x.CallbackUrl == "my_url"), request))
154120
.Returns(expectedResult);
155121
A.CallTo(() => expectedResult.Json).Returns(response);
156122

Tests/xUnitinvi/IntegrationTests/AuthIntegrationTests.cs

+10-10
Original file line numberDiff line numberDiff line change
@@ -76,12 +76,12 @@ public async Task AuthenticateWithPinCode()
7676

7777
// act
7878
var authenticationClient = new TwitterClient(IntegrationTestConfig.TweetinviTest.Credentials);
79-
var authenticationContext = await authenticationClient.Auth.RequestAuthenticationUrl().ConfigureAwait(false);
80-
var authUrl = authenticationContext.AuthorizationURL;
79+
var authenticationRequest = await authenticationClient.Auth.RequestAuthenticationUrl().ConfigureAwait(false);
80+
var authUrl = authenticationRequest.AuthorizationURL;
8181

8282
// ask the user for the pin code
83-
var pinCode = await ExtractPinCodeFromTwitterAuthPage(authUrl).ConfigureAwait(false);
84-
var userCredentials = await authenticationClient.Auth.RequestCredentials(pinCode, authenticationContext).ConfigureAwait(false);
83+
var verifierCode = await ExtractPinCodeFromTwitterAuthPage(authUrl).ConfigureAwait(false);
84+
var userCredentials = await authenticationClient.Auth.RequestCredentialsFromVerifierCode(verifierCode, authenticationRequest).ConfigureAwait(false);
8585
var authenticatedClient = new TwitterClient(userCredentials);
8686
var authenticatedUser = await authenticatedClient.Account.GetAuthenticatedUser().ConfigureAwait(false);
8787

@@ -138,22 +138,22 @@ public async Task AuthenticateWithReadOnlyPermissions()
138138
Assert.Equal(authenticatedUser.ScreenName, IntegrationTestConfig.ProtectedUser.AccountId);
139139
}
140140

141-
private async Task<TwitterClient> GetAuthenticatedTwitterClientViaRedirect(ITwitterClient client, IAuthenticationRequestToken authRequestToken)
141+
private async Task<TwitterClient> GetAuthenticatedTwitterClientViaRedirect(ITwitterClient client, IAuthenticationRequest authRequest)
142142
{
143143
var expectAuthRequestTask = AExtensions.HttpRequest(new AssertHttpRequestConfig(_logger.WriteLine))
144144
.OnPort(8042)
145145
.WithATimeoutOf(TimeSpan.FromSeconds(30))
146-
.Matching(request => { return request.Url.AbsoluteUri.Contains(authRequestToken.AuthorizationKey); })
146+
.Matching(request => { return request.Url.AbsoluteUri.Contains(authRequest.AuthorizationKey); })
147147
.MustHaveHappened();
148148

149-
await AuthenticateWithRedirectUrlOnTwitterAuthPage(authRequestToken.AuthorizationURL, authRequestToken.AuthorizationKey).ConfigureAwait(false);
149+
await AuthenticateWithRedirectUrlOnTwitterAuthPage(authRequest.AuthorizationURL, authRequest.AuthorizationKey).ConfigureAwait(false);
150150

151-
var authRequest = await expectAuthRequestTask.ConfigureAwait(false);
151+
var authHttpRequest = await expectAuthRequestTask.ConfigureAwait(false);
152152

153153
// Ask the user to enter the pin code given by Twitter
154-
var callbackUrl = authRequest.Url.AbsoluteUri;
154+
var callbackUrl = authHttpRequest.Url.AbsoluteUri;
155155

156-
var userCredentials = await client.Auth.RequestCredentialsFromCallbackUrl(callbackUrl, authRequestToken).ConfigureAwait(false);
156+
var userCredentials = await client.Auth.RequestCredentialsFromCallbackUrl(callbackUrl, authRequest).ConfigureAwait(false);
157157
var authenticatedClient = new TwitterClient(userCredentials);
158158
return authenticatedClient;
159159
}

Tweetinvi.Controllers/Auth/AuthController.cs

+5-19
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
using Tweetinvi.Controllers.Properties;
44
using Tweetinvi.Core.Controllers;
55
using Tweetinvi.Core.DTO;
6-
using Tweetinvi.Core.Extensions;
76
using Tweetinvi.Core.Web;
87
using Tweetinvi.Credentials.Models;
98
using Tweetinvi.Exceptions;
@@ -30,29 +29,16 @@ public Task<ITwitterResult<CreateTokenResponseDTO>> CreateBearerToken(ITwitterRe
3029
return _authQueryExecutor.CreateBearerToken(request);
3130
}
3231

33-
public async Task<ITwitterResult<IAuthenticationRequestToken>> RequestAuthUrl(IRequestAuthUrlParameters parameters, ITwitterRequest request)
32+
public async Task<ITwitterResult<IAuthenticationRequest>> RequestAuthUrl(IRequestAuthUrlParameters parameters, ITwitterRequest request)
3433
{
35-
var authToken = new AuthenticationRequestToken(request.Query.TwitterCredentials)
36-
{
37-
Id = parameters.RequestId
38-
};
34+
var authToken = new AuthenticationRequest(request.Query.TwitterCredentials);
3935

4036
var authProcessParams = new RequestAuthUrlInternalParameters(parameters, authToken);
4137

4238
if (string.IsNullOrEmpty(parameters.CallbackUrl))
4339
{
4440
authProcessParams.CallbackUrl = Resources.Auth_PinCodeUrl;
4541
}
46-
else if (parameters.RequestId != null)
47-
{
48-
var tweetinviTokenParameterName = parameters.AuthenticationTokenProvider?.CallbackTokenIdParameterName() ?? Resources.Auth_ProcessIdKey;
49-
authProcessParams.CallbackUrl = authProcessParams.CallbackUrl.AddParameterToQuery(tweetinviTokenParameterName, parameters.RequestId);
50-
51-
if (parameters.AuthenticationTokenProvider != null)
52-
{
53-
await parameters.AuthenticationTokenProvider.AddAuthenticationToken(authToken);
54-
}
55-
}
5642

5743
var requestTokenResponse = await _authQueryExecutor.RequestAuthUrl(authProcessParams, request).ConfigureAwait(false);
5844

@@ -72,7 +58,7 @@ public async Task<ITwitterResult<IAuthenticationRequestToken>> RequestAuthUrl(IR
7258
authToken.AuthorizationSecret = tokenInformation.Groups["oauth_token_secret"].Value;
7359
authToken.AuthorizationURL = $"{Resources.Auth_AuthorizeBaseUrl}?oauth_token={authToken.AuthorizationKey}";
7460

75-
return new TwitterResult<IAuthenticationRequestToken>
61+
return new TwitterResult<IAuthenticationRequest>
7662
{
7763
Request = requestTokenResponse.Request,
7864
Response = requestTokenResponse.Response,
@@ -92,8 +78,8 @@ public async Task<ITwitterResult<ITwitterCredentials>> RequestCredentials(IReque
9278
}
9379

9480
var credentials = new TwitterCredentials(
95-
parameters.AuthRequestToken.ConsumerKey,
96-
parameters.AuthRequestToken.ConsumerSecret,
81+
parameters.AuthRequest.ConsumerKey,
82+
parameters.AuthRequest.ConsumerSecret,
9783
responseInformation.Groups["oauth_token"].Value,
9884
responseInformation.Groups["oauth_token_secret"].Value);
9985

Tweetinvi.Controllers/Auth/AuthQueryExecutor.cs

+3-3
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ public Task<ITwitterResult> RequestAuthUrl(RequestAuthUrlInternalParameters para
4747

4848
request.Query.Url = _queryGenerator.GetRequestAuthUrlQuery(parameters);
4949
request.Query.HttpMethod = HttpMethod.POST;
50-
request.TwitterClientHandler = new AuthHttpHandler(callbackParameter, parameters.AuthRequestToken, oAuthWebRequestGenerator);
50+
request.TwitterClientHandler = new AuthHttpHandler(callbackParameter, parameters.AuthRequest, oAuthWebRequestGenerator);
5151

5252
return _twitterAccessor.ExecuteRequest(request);
5353
}
@@ -59,8 +59,8 @@ public Task<ITwitterResult> RequestCredentials(IRequestCredentialsParameters par
5959

6060
request.Query.Url = _queryGenerator.GetRequestCredentialsQuery(parameters);
6161
request.Query.HttpMethod = HttpMethod.POST;
62-
request.Query.TwitterCredentials = new TwitterCredentials(parameters.AuthRequestToken.ConsumerKey, parameters.AuthRequestToken.ConsumerSecret);
63-
request.TwitterClientHandler = new AuthHttpHandler(callbackParameter, parameters.AuthRequestToken, oAuthWebRequestGenerator);
62+
request.Query.TwitterCredentials = new TwitterCredentials(parameters.AuthRequest.ConsumerKey, parameters.AuthRequest.ConsumerSecret);
63+
request.TwitterClientHandler = new AuthHttpHandler(callbackParameter, parameters.AuthRequest, oAuthWebRequestGenerator);
6464

6565
return _twitterAccessor.ExecuteRequest(request);
6666
}

Tweetinvi.Controllers/Auth/RequestAuthUrlInternalParameters.cs

+3-3
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,11 @@ namespace Tweetinvi.Controllers.Auth
55
{
66
public class RequestAuthUrlInternalParameters : RequestUrlAuthUrlParameters
77
{
8-
public IAuthenticationRequestToken AuthRequestToken { get; }
8+
public IAuthenticationRequest AuthRequest { get; }
99

10-
public RequestAuthUrlInternalParameters(IRequestAuthUrlParameters parameters, IAuthenticationRequestToken authRequestToken) : base(parameters)
10+
public RequestAuthUrlInternalParameters(IRequestAuthUrlParameters parameters, IAuthenticationRequest authRequest) : base(parameters)
1111
{
12-
AuthRequestToken = authRequestToken;
12+
AuthRequest = authRequest;
1313
}
1414
}
1515
}

Tweetinvi.Core/Core/Client/Validators/AuthClientRequiredParametersValidator.cs

+6-11
Original file line numberDiff line numberDiff line change
@@ -31,11 +31,6 @@ public void Validate(IRequestAuthUrlParameters parameters)
3131
{
3232
throw new ArgumentNullException(nameof(parameters));
3333
}
34-
35-
if (parameters.RequestId == string.Empty)
36-
{
37-
throw new ArgumentException("Cannot be empty", $"{nameof(parameters)}{nameof(parameters.RequestId)}");
38-
}
3934
}
4035

4136
public void Validate(IRequestCredentialsParameters parameters)
@@ -50,19 +45,19 @@ public void Validate(IRequestCredentialsParameters parameters)
5045
throw new ArgumentNullException($"{nameof(parameters)}{nameof(parameters.VerifierCode)}", "If you received a null verifier code, the authentication failed");
5146
}
5247

53-
if (parameters.AuthRequestToken == null)
48+
if (parameters.AuthRequest == null)
5449
{
55-
throw new ArgumentNullException($"{nameof(parameters)}{nameof(parameters.AuthRequestToken)}");
50+
throw new ArgumentNullException($"{nameof(parameters)}{nameof(parameters.AuthRequest)}");
5651
}
5752

58-
if (string.IsNullOrEmpty(parameters.AuthRequestToken.ConsumerKey))
53+
if (string.IsNullOrEmpty(parameters.AuthRequest.ConsumerKey))
5954
{
60-
throw new ArgumentNullException($"{nameof(parameters)}{nameof(parameters.AuthRequestToken)}{nameof(parameters.AuthRequestToken.ConsumerKey)}");
55+
throw new ArgumentNullException($"{nameof(parameters)}{nameof(parameters.AuthRequest)}{nameof(parameters.AuthRequest.ConsumerKey)}");
6156
}
6257

63-
if (string.IsNullOrEmpty(parameters.AuthRequestToken.ConsumerSecret))
58+
if (string.IsNullOrEmpty(parameters.AuthRequest.ConsumerSecret))
6459
{
65-
throw new ArgumentNullException($"{nameof(parameters)}{nameof(parameters.AuthRequestToken)}{nameof(parameters.AuthRequestToken.ConsumerSecret)}");
60+
throw new ArgumentNullException($"{nameof(parameters)}{nameof(parameters.AuthRequest)}{nameof(parameters.AuthRequest.ConsumerSecret)}");
6661
}
6762
}
6863
}

0 commit comments

Comments
 (0)