I am trying to implement external OAuth in Asp.Net Core (https://github.com/aspnet-contrib/AspNet.Security.OAuth.Providers). My application (GitLab) has Callback URL https://myhost.com/signin-gitlab (default used by middleware).
If I run the code below, I get "Exception: The oauth state was missing or invalid." However, if I remove "options.UserInformationEndpoint" from Startup.cs, then I get redirected to myhost.com/signin-gitlab with the code and state parameters, which the middleware should exchange for an access token. My question is, why does my state parameter get corrupted (with UserInformationEndpoint)? Why am I not getting an access token? What am I missing here?
My Startup class:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Authentication.OAuth;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using AspNet.Security.OAuth.GitLab;
using System.Net.Http;
using System.Net.Http.Headers;
namespace MyApp
{
public class Startup
{
private readonly IConfiguration _cfg;
public Startup(IConfiguration configuration) => _cfg = configuration;
public void ConfigureServices(IServiceCollection services)
{
services.AddRouting();
services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
.AddCookie()
.AddGitLab("Gitlab", options => {
options.ClientId = "...";
options.ClientSecret = "...";
options.AuthorizationEndpoint = "https://mygitlabserver.com/oauth/authorize";
options.TokenEndpoint = "https://mygitlabserver.com/oauth/token";
options.Scope.Clear();
options.Scope.Add("api");
options.SaveTokens = true;
options.SignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
options.UserInformationEndpoint = "https://mygitlabserver.com/api/v4/user";
});
services.AddMvc();
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseDeveloperExceptionPage();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapDefaultControllerRoute();
});
}
}
}
My Controller:
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Mvc;
namespace MyApp.Controllers
{
public class HomeController : Controller
{
[HttpGet("/")]
public IActionResult Index()
{
return View();
}
[HttpGet("/login")]
public IActionResult LogIn()
{
// Instruct the middleware corresponding to the requested external identity
// provider to redirect the user agent to its own authorization endpoint.
// Note: the authenticationScheme parameter must match the value configured in Startup.cs
return Challenge(new AuthenticationProperties { RedirectUri = "https://myhost.com/signin-gitlab" }, "Gitlab");
}
}
}
First of all, ASP.NET external identity provider/social login is either done with or without Identity Framework. Without Identity, it should be setup like so (https://learn.microsoft.com/en-us/aspnet/core/security/authentication/social/social-without-identity?view=aspnetcore-5.0):
The second issue was inside the controller:
Just as in the MVC Sample app by the aspnet-contrib team (https://github.com/aspnet-contrib/AspNet.Security.OAuth.Providers/blob/dev/samples/Mvc.Client/Controllers/AuthenticationController.cs) it should actually be:
Users were actually being authenticated, the problem was that they were then redirected to the OAuth middleware's internal route /signin-gitlab without state or code parameters instead of the home route/index action, hence the error.
In other words, I mixed up:
Perhaps my confusion was caused by the fact that the callback url is called REDIRECT_URI in the GitLab docs (https://docs.gitlab.com/ee/api/oauth2.html).
Thanks to Nan Yu (https://stackoverflow.com/a/61452853/2768479) and Tratcher (https://github.com/dotnet/aspnetcore/issues/22125, https://github.com/aspnet/Security/issues/1756) for their illuminating posts.