C# Academy · Lesson

Issuing Tokens

Generate signed tokens on login.

Lesson 3 of 413 steps

Issuing Tokens is a free C# Academy lesson on CoddyKit. This is lesson 3 of 4. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the C# Academy learning path, and your progress syncs across the web and the CoddyKit app. The C# Academy course includes 4 lessons in total.

Issuing Versus Validating

So far you validated tokens. Now you will issue them: after a user logs in successfully, your API mints a signed JWT and returns it.

The core type for this is JwtSecurityTokenHandler from System.IdentityModel.Tokens.Jwt.

dotnet add package System.IdentityModel.Tokens.Jwt

The Signing Key

To sign a token you need a key. For HS256 you reuse the same symmetric secret the validator uses.

Keep this secret out of source control - load it from configuration or a secret store.

var key = new SymmetricSecurityKey(
    Encoding.UTF8.GetBytes(configuration["Jwt:Key"]!));

SigningCredentials

SigningCredentials pairs the key with the algorithm. For a symmetric key, use SecurityAlgorithms.HmacSha256.

var creds = new SigningCredentials(
    key,
    SecurityAlgorithms.HmacSha256);

Building the Claims

Decide what goes into the token. Always include a subject (the user id) and any roles or data the API needs.

Add a unique jti so each token can be identified.

var claims = new List<Claim>
{
    new Claim(JwtRegisteredClaimNames.Sub, user.Id.ToString()),
    new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),
    new Claim(ClaimTypes.Name, user.UserName),
    new Claim(ClaimTypes.Role, user.Role)
};

Creating the JwtSecurityToken

JwtSecurityToken bundles the issuer, audience, claims, expiry and signing credentials into a token object.

var token = new JwtSecurityToken(
    issuer: configuration["Jwt:Issuer"],
    audience: configuration["Jwt:Audience"],
    claims: claims,
    notBefore: DateTime.UtcNow,
    expires: DateTime.UtcNow.AddMinutes(15),
    signingCredentials: creds);

Serializing to a String

The token object must be written to its compact header.payload.signature string form before sending it to the client.

var handler = new JwtSecurityTokenHandler();
string jwt = handler.WriteToken(token);
// jwt now looks like eyJhbGciOiJI...

A Reusable Token Service

Wrap the logic in a service so controllers stay clean and the configuration lives in one place.

public class TokenService(IConfiguration config)
{
    public string CreateAccessToken(AppUser user)
    {
        var key = new SymmetricSecurityKey(
            Encoding.UTF8.GetBytes(config["Jwt:Key"]!));
        var creds = new SigningCredentials(
            key, SecurityAlgorithms.HmacSha256);
        var claims = new[]
        {
            new Claim(JwtRegisteredClaimNames.Sub, user.Id.ToString()),
            new Claim(ClaimTypes.Role, user.Role)
        };
        var token = new JwtSecurityToken(
            config["Jwt:Issuer"], config["Jwt:Audience"],
            claims, expires: DateTime.UtcNow.AddMinutes(15),
            signingCredentials: creds);
        return new JwtSecurityTokenHandler().WriteToken(token);
    }
}

Wiring the Login Endpoint

The login endpoint verifies credentials, then calls the service and returns the token to the client.

app.MapPost("/login", (LoginDto dto, TokenService tokens) =>
{
    var user = Authenticate(dto.Username, dto.Password);
    if (user is null) return Results.Unauthorized();
    return Results.Ok(new { accessToken = tokens.CreateAccessToken(user) });
});

Symmetric Versus Asymmetric

HS256 uses one shared secret for both signing and validating. RS256 uses a private key to sign and a public key to validate.

Asymmetric signing lets you publish the public key so other services validate tokens without ever holding the signing secret.

var creds = new SigningCredentials(
    new RsaSecurityKey(rsaPrivateKey),
    SecurityAlgorithms.RsaSha256);

Registering the Service

Add the token service to dependency injection so it can be injected into endpoints and controllers.

builder.Services.AddScoped<TokenService>();

Keep Tokens Lean and Short

Two best practices when issuing tokens:

  • Lean: include only claims the API needs - the token travels on every request.
  • Short-lived: 5 to 15 minute access tokens limit the damage if one leaks.
expires: DateTime.UtcNow.AddMinutes(15)

Quick Check

Confirm what you learned about issuing tokens.

Recap

You issued signed JWTs:

  • SigningCredentials pairs your key with an algorithm.
  • Build a list of Claims, then a JwtSecurityToken with issuer, audience and expiry.
  • JwtSecurityTokenHandler.WriteToken serializes it to the compact string.
  • Keep tokens lean and short-lived.

Next: refresh tokens and expiry strategies.

Free to start

Learn C# with an AI tutor — free

Write and run real code in your browser, get instant help from a 24/7 AI tutor, and pick up where you left off on the web or in the app.

Courses
93
Lessons
346

Frequently Asked Questions

Is the “Issuing Tokens” lesson free?

Yes — the full text of “Issuing Tokens” is free to read here on the web. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the C# Academy course, upgrade to CoddyKit PRO. The C# Academy course includes 4 lessons in total.

What will I learn in “Issuing Tokens”?

Generate signed tokens on login. You practise C# Academy with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.

Do I need any experience to start C# Academy?

No prior experience is required. C# Academy on CoddyKit is structured for beginners through advanced learners, so you can start here or from the beginning and move at your own pace. This is lesson 3 of 4.

How long does the “Issuing Tokens” lesson take?

Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.

Can I write and run code in this C# Academy lesson?

Yes. Every C# Academy lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.

All lessons in this course

  1. JWT Structure and Claims
  2. Configuring JWT Bearer Authentication
  3. Issuing Tokens
  4. Refresh Tokens and Expiry
← Back to C# Academy