Skip to Content

How to pass token in header using C#?

Passing tokens in headers is a common requirement in many web applications and APIs that require authentication and authorization. By passing a token in the header, the server can validate the request and allow access to protected resources and endpoints. In C#, there are a few different ways to add a token to the header of an HTTP request.

What is an Authorization Token?

An authorization token is a string of characters that acts as an identifier for a user or service. It is generated on the server and then passed to the client, which then passes it back to the server on subsequent requests. This allows the server to validate that the request is coming from an authorized source.

Some common examples of tokens include:

  • JSON Web Tokens (JWT)
  • OAuth access tokens
  • Session IDs

These tokens contain information encoded into them such as the user ID, permissions, and expiration time. They are digitally signed to prevent tampering.

Benefits of Using Tokens

There are several benefits to using tokens for authentication instead of other mechanisms like cookies:

  • Stateless – The server does not need to store session data for each client. The token contains all the necessary information to identify the user.
  • More Secure – Tokens can be encrypted and digitally signed to prevent tampering.
  • Easier Scaling – Stateless auth makes it easier to add more servers without worrying about session replication.
  • Decoupled – The authorization logic is separate from session management.
  • Standardized – Standard token formats like JWT are widely supported.

Methods for Passing a Token in C#

Here are some common ways to pass an authorization token in the header of an HTTP request in C#:

1. Add Header Directly to HttpClient

The HttpClient class allows you to set a default header value that will be sent with every request. You can set the Authorization header with the Bearer token when creating the HttpClient:


// Create HttpClient
HttpClient client = new HttpClient();

// Set default Authorization header
client.DefaultRequestHeaders.Authorization = 
    new AuthenticationHeaderValue("Bearer", token);

// Send request
HttpResponseMessage response = await client.GetAsync(url); 

This is useful if you want to apply the same authorization token to all requests sent through this client instance.

2. Add Header to Individual HttpRequestMessage

You can also add the Authorization header to individual HttpRequestMessage objects when making each request:


// Create request message
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, url);

// Add Authorization header 
request.Headers.Authorization = 
    new AuthenticationHeaderValue("Bearer", token); 

// Send request
HttpResponseMessage response = await client.SendAsync(request);

This is useful if you want to use different tokens for each request.

3. Use HttpClientHandler

The HttpClientHandler allows modifying requests before they are sent. You can add the Authorization token in the ServerCertificateCustomValidationCallback method:


HttpClientHandler handler = new HttpClientHandler();
handler.ServerCertificateCustomValidationCallback = (message, cert, chain, errors) => 
{
    message.Headers.Authorization = 
        new AuthenticationHeaderValue("Bearer", token);
    return true;
};

HttpClient client = new HttpClient(handler);

// Send request
HttpResponseMessage response = await client.GetAsync(url);

This allows setting a default token that will apply to all requests, while keeping the HttpClient token-agnostic.

4. Use HttpClient Factory

If you are using the IHttpClientFactory to manage HttpClient instances, you can create a typed client with a delegating handler to add the token:


// Token handler
public class TokenHandler : DelegatingHandler
{
  private string token;

  public TokenHandler(string token)
  {
    this.token = token;
  }

  protected override Task SendAsync(
    HttpRequestMessage request, 
    CancellationToken cancellationToken)
  {
    // Add token
    request.Headers.Authorization = 
      new AuthenticationHeaderValue("Bearer", token);
    
    // Call next handler
    return base.SendAsync(request, cancellationToken); 
  }
}

// Register typed client
services.AddHttpClient("api")
    .AddHttpMessageHandler(token);

This allows injecting the typed client where needed and the token will automatically be applied.

Passing the Token in POST Requests

When making POST, PUT, or PATCH requests, it is common to pass the token in the request body rather than the header. For example, when calling an API you would structure the request like:


POST /api/endpoint
{
  "token": "TOKEN_VALUE",
  "some": "payload" 
}

To do this in C#, you need to serialize the token into the request content:


// Create request
var request = new HttpRequestMessage(HttpMethod.Post, url);

// Set request content 
request.Content = new StringContent(JsonConvert.SerializeObject(new {
  token = token,
  some = "payload"  
}), Encoding.UTF8, "application/json");

// Send request
var response = await client.SendAsync(request);

This will JSON serialize the payload with the token included.

Validating the Token in the API

On the server-side, the API will need to implement token validation logic to authenticate requests. Here are some typical steps:

  1. Extract the token from the header or request body
  2. Verify the token format and signature
  3. Decode the token and validate fields like issuer, expiry time, etc
  4. Lookup the user by the user id contained in the token
  5. Check that user has required permissions

Common ways to implement token validation in ASP.NET Core:

JWT Middleware

Use the JWT middleware to automatically validate the token and populate ClaimsPrincipal:


public void Configure(IApplicationBuilder app)
{
  app.UseAuthentication();

  app.UseJwtBearerAuthentication(options => {
    options.TokenValidationParameters = GetValidationParameters(); 
  });
}

public TokenValidationParameters GetValidationParameters() 
{
  return new TokenValidationParameters {
    // Configure parameters like issuer, audience, clock skew, etc
  };
}

Custom Middleware

Implement custom middleware to decode and validate the token:


public class CustomJwtMiddleware
{
  public async Task Invoke(HttpContext context)
  {
    var token = context.Request.Headers["Authorization"].FirstOrDefault()?.Split(" ").Last();

    if (token != null)
    {
      var principal = ValidateToken(token); 
      context.User = principal;
    }

    await _next(context);
  }

  private ClaimsPrincipal ValidateToken(string token)
  {
    // Implement token validation and decoding 
  }
}

Action Filters

Decode and validate token in an authorization filter:


public class JwtAuthorizationFilter : IAuthorizationFilter 
{
  public void OnAuthorization(AuthorizationFilterContext context)
  {
    var token = context.HttpContext.Request.Headers["Authorization"].FirstOrDefault()?.Split(" ").Last();

    if (token != null)
    {
       var principal = ValidateToken(token);
       context.HttpContext.User = principal; 
    }
  }
}

The principal will then be available for authorization policies and identity checks.

Refreshing Expired Tokens

Tokens issued by authorization servers often have a short expiry time. Once expired, requests with that token will start failing.

To avoid interruption, the client can proactively refresh the token before it expires by making a request to the token endpoint:


// Request new access token
var refreshToken = GetSavedRefreshToken();

var request = new HttpRequestMessage(HttpMethod.Post, "https://auth.example/token");
request.Content = new FormUrlEncodedContent(new Dictionary {
    ["grant_type"] = "refresh_token",
    ["refresh_token"] = refreshToken
});

var response = await client.SendAsync(request);

// Extract and save new access token 
var newToken = ExtractToken(response); 
SaveToken(newToken);

The client should request a new access token in this way once the old token expires or is close to expiry.

To handle expiry seamlessly, the client could:

  • Store the expiry time of the access token on retrieve
  • Set a timer to refresh at a certain time before expiry (e.g. 5 minutes)
  • Retry requests with a new access token if they fail due to expiry

Common Issues

Here are some common issues faced when passing tokens in headers and how to resolve them:

401 Unauthorized Response

A 401 error indicates the request was unauthorized, which generally means the token is invalid, expired or not being passed correctly.

Things to check:

  • Verify the token value is correct
  • Make sure the token is not expired and refresh if needed
  • Confirm the token is passed in the correct Authorization header format
  • Check the API accepts the given token type (e.g. Bearer)

403 Forbidden Response

A 403 forbidden error means the token is valid but the user does not have permission to access the requested resource.

To resolve, you need to:

  • Check the user has the required roles/claims
  • Confirm the scopes in the token allow access to the resource
  • Request the token again with sufficient access scopes

No Authorization Header

If the token is not being passed at all, the API will not see an Authorization header.

Make sure to check:

  • The header name is spelled correctly
  • The header is being set on request messages
  • The token value is resolving correctly

Invalid Token Format

If an incorrectly formatted token is passed, the API will fail to decode and validate it.

Verify:

  • The token is generated correctly by the server
  • Special characters are escaped properly
  • The client is not accidentally corrupting the token format

Conclusion

Passing authentication and authorization tokens in HTTP headers is a common practice for securing web APIs and enabling client applications to access user data.

In C#, tokens can be added to requests using various approaches including setting default headers on HttpClient, adding headers to individual messages, using handlers and filters, and serializing tokens in request bodies.

The token should be validated on the server before allowing access to protected resources. Common validation steps include verifying the signature, decoding the claims, and checking permissions.

Following best practices around token usage and validation allows building robust, secure systems decoupled from session state.