Issuing Tokens
Generate signed tokens on login.
Issuing Tokens is a free C# Academy lesson on CoddyKit — 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, one of 4 lessons in the course, and your progress syncs across the web and the CoddyKit app.
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.JwtThe 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:
SigningCredentialspairs your key with an algorithm.- Build a list of
Claims, then aJwtSecurityTokenwith issuer, audience and expiry. JwtSecurityTokenHandler.WriteTokenserializes it to the compact string.- Keep tokens lean and short-lived.
Next: refresh tokens and expiry strategies.
Frequently asked questions
Is the “Issuing Tokens” lesson free?
Yes — the full text of “Issuing Tokens” is free to read here on the web, and the C# Academy course includes 4 lessons in total. 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.
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; this is — lesson 3 of 4, so you can start here or from the beginning and move at your own pace.
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.