83

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?}");
});
9
  • You don't have to register HttpContext. It's already available in your controller classes just like in 1.1. Commented Apr 11, 2018 at 7:23
  • @Brad thats what i thought but i am not able to access it please describe what you mean. Commented Apr 11, 2018 at 7:24
  • Is your controller inheriting from class Controller? Commented Apr 11, 2018 at 7:27
  • If GetAccessToken() returns null it's likely an issue in your authentication config. How have you configured authentication in Startup? Commented Apr 11, 2018 at 7:29
  • 1
    ClientUpdate is in the same ConsoleController so i would have to say yes? Commented Apr 11, 2018 at 7:30

10 Answers 10

120

.Net core 2.1 to access JWT bearer token

var accessToken = Request.Headers[HeaderNames.Authorization];
Sign up to request clarification or add additional context in comments.

11 Comments

@El Mac apparently, I was missing options.SaveTokens = true in the AddOpenIdConnect method inside Startup.ConfigureServices. stackoverflow.com/a/50623141/2632991
This doesn't return just the token. It also include the auth scheme from the header ("Bearer "), so if you want just the token you have to extract it
Is there any way to NOT hard-code the "Authorization" string? Is that string defined somewhere as a constant or enum?
Where does the Request come from?
|
55

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;

2 Comments

Very crisp. Wrapping under try...catch would be recommended, optional though.
Use "HttpContext.GetTokenAsync("access_token")" instead.
35

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

4 Comments

You don't need IHttpContextAccessor in your controller. It's already there as the HttpContext property.
It was! Your configuration was incorrect as this answer clearly suggests. You would have been getting NullReferenceException if HttpContext wasn't populated. And this is what i meant by authentication configuration!
Where did you get access_token name? Is it some well-known propertly? Can you please share reference to the docs?
Yes access token is standard. Its part of the response. from authorization.
30

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();
}

Comments

5

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

1 Comment

Works for me with var token = HttpContext.Request.Headers["Authorization"][0]; @user1672994 made a small typo Authorziation should be Authorization
2

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

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

Comments

2
string accessToken = Request.Headers[HeaderNames.Authorization].ToString().Replace($"{JwtBearerDefaults.AuthenticationScheme} ", String.Empty);

Comments

0

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";

Comments

0

My project targeting .Net 7

string? jwtToken = HttpContext.Request.Headers.Authorization.FirstOrDefault()?.Split(" ").Last();

Comments

-5

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

1 Comment

Blocking an asynchronous method inside an asynchronous action is a very bad idea. It won't fix any namespace issues either.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.