Skip to content

Commit 985f785

Browse files
Handle user cancelling LinkedIn sign in
Handle the user cancelling login or denying permissions during LinkedIn sign in. Resolves #480.
1 parent 55229e8 commit 985f785

File tree

1 file changed

+56
-0
lines changed

1 file changed

+56
-0
lines changed

src/AspNet.Security.OAuth.LinkedIn/LinkedInAuthenticationHandler.cs

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
using Microsoft.AspNetCore.WebUtilities;
1919
using Microsoft.Extensions.Logging;
2020
using Microsoft.Extensions.Options;
21+
using Microsoft.Extensions.Primitives;
2122

2223
namespace AspNet.Security.OAuth.LinkedIn
2324
{
@@ -115,5 +116,60 @@ protected override async Task<AuthenticationTicket> CreateTicketAsync(
115116
.Select((p) => p.GetString("emailAddress"))
116117
.FirstOrDefault();
117118
}
119+
120+
protected override async Task<HandleRequestResult> HandleRemoteAuthenticateAsync()
121+
{
122+
// Taken from the base class' implementation so we can modify the status code check
123+
// for "access denied" as LinkedIn uses non-standard error codes (see https://github.com/aspnet-contrib/AspNet.Security.OAuth.Providers/issues/480).
124+
// https://github.com/dotnet/aspnetcore/blob/bbf7c8780c42e3d32aeec8018367037784eb9181/src/Security/Authentication/OAuth/src/OAuthHandler.cs#L49-L87
125+
var query = Request.Query;
126+
127+
var state = query["state"];
128+
var properties = Options.StateDataFormat.Unprotect(state);
129+
130+
if (properties == null)
131+
{
132+
return HandleRequestResult.Fail("The oauth state was missing or invalid.");
133+
}
134+
135+
// OAuth2 10.12 CSRF
136+
if (!ValidateCorrelationId(properties))
137+
{
138+
return HandleRequestResult.Fail("Correlation failed.", properties);
139+
}
140+
141+
var error = query["error"];
142+
if (!StringValues.IsNullOrEmpty(error))
143+
{
144+
// Note: access_denied errors are special protocol errors indicating the user didn't
145+
// approve the authorization demand requested by the remote authorization server.
146+
// Since it's a frequent scenario (that is not caused by incorrect configuration),
147+
// denied errors are handled differently using HandleAccessDeniedErrorAsync().
148+
// Visit https://tools.ietf.org/html/rfc6749#section-4.1.2.1 for more information.
149+
var errorDescription = query["error_description"];
150+
var errorUri = query["error_uri"];
151+
152+
// See https://docs.microsoft.com/en-us/linkedin/shared/authentication/authorization-code-flow#application-is-rejected
153+
if (StringValues.Equals(error, "access_denied") ||
154+
StringValues.Equals(error, "user_cancelled_login") ||
155+
StringValues.Equals(error, "user_cancelled_authorize"))
156+
{
157+
var result = await HandleAccessDeniedErrorAsync(properties);
158+
if (!result.None)
159+
{
160+
return result;
161+
}
162+
163+
var deniedEx = new Exception("Access was denied by the resource owner or by the remote server.");
164+
deniedEx.Data["error"] = error.ToString();
165+
deniedEx.Data["error_description"] = errorDescription.ToString();
166+
deniedEx.Data["error_uri"] = errorUri.ToString();
167+
168+
return HandleRequestResult.Fail(deniedEx, properties);
169+
}
170+
}
171+
172+
return await base.HandleRemoteAuthenticateAsync();
173+
}
118174
}
119175
}

0 commit comments

Comments
 (0)