How to get access token from HttpContext in .Net core 2.0

C#Httpasp.net Core.Net Core

C# Problem Overview


I'm trying to upgrade a project from .Net core 1.1 to .Net core 2.0 there's a lot of breaking changes.

One of the things I'm currently having an issue with is that HttpContext.Authentication is now obsolete.

I've been trying to figure out how to get the Access token for the current request. I need to make a call to another API which requires a bearer token.

Old Method .Net core 1.1

[Authorize]
public async Task<IActionResult> ClientUpdate(ClientModel client)
{
    var accessToken = await HttpContext.Authentication.GetTokenAsync("access_token");
    return View();
}

Method .Net core 2.0

This is not working becouse context isnt registered.

[Authorize]
public async Task<IActionResult> ClientUpdate(ClientModel client)
{
    var accessToken = await context.HttpContext.GetTokenAsync("access_token"); 
    return View();
}

> Unable to resolve service for type 'Microsoft.AspNetCore.Http.HttpContext'

I tried registering it but that doesnt work either

public ConsoleController(IOptions<ServiceSettings> serviceSettings, HttpContext context) 

In startup.cs

services.TryAddSingleton<HttpContext, HttpContext>();

Update:

This returns null

var accessToken = await HttpContext.GetTokenAsync("access_token");  

Startup.cs ConfigureServices

I wouldn't be surprised if it was something in the startup as there were a lot of breaking changes here as well.

services.Configure<ServiceSettings>(Configuration.GetSection("ServiceSettings"));
//services.TryAddSingleton<HttpContext, HttpContext>();
services.TryAddSingleton<IHttpContextAccessor, HttpContextAccessor>();
services.AddMvc();
services.AddAuthentication(options =>
        {
            options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
            options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
        })
        .AddCookie()
        .AddOpenIdConnect(options =>
        {
            options.Authority = "http://localhost:5000";
            options.ClientId = "testclient";
            options.ClientSecret = "secret";
            options.ResponseType = "code id_token";
            options.RequireHttpsMetadata = false;
            options.GetClaimsFromUserInfoEndpoint = true;
        });

Startup.cs Configure

loggerFactory.AddDebug();
if (env.IsDevelopment())
{
    app.UseDeveloperExceptionPage();
    app.UseBrowserLink();
}
else
{
    app.UseExceptionHandler("/Home/Error");
}
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();
app.UseStaticFiles();
app.UseAuthentication();
app.UseMvc(routes =>
{
    routes.MapRoute(
        name: "default",
        template: "{controller=Home}/{action=Index}/{id?}");
});

C# Solutions


Solution 1 - C#

.Net core 2.1 to access JWT bearer token

var accessToken = Request.Headers[HeaderNames.Authorization];

Solution 2 - C#

if you want the pure token this can help you in .net core 3.1

var _bearer_token = Request.Headers[HeaderNames.Authorization].ToString().Replace("Bearer ", "");

and remember you need to add this using

using Microsoft.Net.Http.Headers;

Solution 3 - C#

It ended up being a configuration issue. There needs to be a link between AddAuthentication and AddOpenIdConnect in order for it to read the cookie into the headers.

services.TryAddSingleton<IHttpContextAccessor, HttpContextAccessor>();

services.AddAuthentication(options =>
            {
                options.DefaultScheme = "Cookies";
                options.DefaultChallengeScheme = "oidc";
            })
            .AddCookie("Cookies")
            .AddOpenIdConnect("oidc", options =>
            {
                options.SignInScheme = "Cookies";

                options.Authority = "http://localhost:5000";
                options.RequireHttpsMetadata = false;

                options.ClientId = "testclient";
                options.ClientSecret = "secret";
                options.ResponseType = "code id_token";
                options.SaveTokens = true;
                options.GetClaimsFromUserInfoEndpoint = true;

                options.Scope.Add("testapi");
                options.Scope.Add("offline_access");
            });

Controller

    [Authorize]
    public async Task<IActionResult> Index()
    {
        var accessToken = await HttpContext.GetTokenAsync("access_token");
        return View();
    }

Access token is now populated.

Note: I ended up digging it out of this project Startup.cs

Solution 4 - C#

In Controller, the token can be retrieved by reading Request.Headers dictionary:

 var accessToken = Request.Headers["Authorization"];

At other classes where HttpContext is not available, there token can be retrieved using HttpContextAccessor after injecting into services collection ( A little change from Azharuddin answer)

Register the service instance in Startup method like

public void ConfigureServices(IServiceCollection services)
{

 services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
 ...
}

And inject the dependency in your controller like

private IHttpContextAccessor _httpContextAccessor;
public ClientController(IHttpContextAccessor httpContextAccessor)
{
     _httpContextAccessor = httpContextAccessor;
}

And retrieve the access token in your action like

[Authorize]
public async Task<IActionResult> ClientUpdate(ClientModel client)
{
    var accessToken = _httpContextAccessor.HttpContext.Request.Headers["Authorization"];

    ..........//Some other code
    return View();
}

Solution 5 - C#

Startup.cs:

 public void ConfigureServices(IServiceCollection services)
 {
    ...
     services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
    ...
 }

Controller Constructor:

private IHttpContextAccessor _httpContextAccessor;
public ClientController(IHttpContextAccessor httpContextAccessor)
{
     _httpContextAccessor = httpContextAccessor;
}

[Authorize]
public async Task<IActionResult> ClientUpdate(ClientModel client)
{
    var accessToken = await _httpContextAccessor.HttpContext.GetTokenAsync("access_token");
    return View();
}

This should work

Solution 6 - C#

You need to specify the external schema to retrieve the token.

var accessToken = await HttpContext.GetTokenAsync(IdentityConstants.ExternalScheme, "access_token");

Solution 7 - C#

Real thanks, this is perfect !

I had this work, but with our azure tenant dedicated authority. Simply replace ****** with your tenant name.

options.Authority = "https://login.microsoftonline.com/******.onmicrosoft.com";

You also can use tenant id. Simply insert your tenant id after https://login.microsoftonline.com/

options.Authority = "https://login.microsoftonline.com/be0be093-****-****-****-5626e83beefc";

Solution 8 - C#

it should be HttpContext.GetTokenAsync("access_token").Result.ToString();

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionDaImToView Question on Stackoverflow
Solution 1 - C#Chpn DaveView Answer on Stackoverflow
Solution 2 - C#DiegoView Answer on Stackoverflow
Solution 3 - C#DaImToView Answer on Stackoverflow
Solution 4 - C#user1672994View Answer on Stackoverflow
Solution 5 - C#azharuddin irfaniView Answer on Stackoverflow
Solution 6 - C#William MagnoView Answer on Stackoverflow
Solution 7 - C#AlboView Answer on Stackoverflow
Solution 8 - C#bi2monView Answer on Stackoverflow