0Pricing
C# Academy · 강의

새로 고침 토큰과 만료

안전한 토큰 갱신을 구현합니다.

새로 고침 토큰과 만료은(는) CoddyKit의 무료 C# Academy 강의입니다. 이것은 4개 중 4번째 강의입니다. 아래에서 전체 강의를 무료로 읽을 수 있으며, 내장 코드 에디터와 24/7 AI 튜터와 함께 브라우저에서 직접 실습할 수 있습니다. 이 강의는 C# Academy 학습 경로의 일부이며, 진행 상황이 웹과 CoddyKit 앱에 동기화됩니다. C# Academy 강의에는 총 4개의 강의가 포함되어 있습니다.

만료 문제

수명이 짧은 access token은 안전하지만 불편합니다. 사용자에게 15분마다 로그인하도록 요구하는 것은 사용자 경험에 좋지 않습니다.

해결책은 refresh token입니다. 이는 비밀번호를 다시 입력하지 않고 새 access token을 얻는 데 사용하는 별도의, 수명이 더 긴 자격 증명입니다.

// access token: 15 minutes
// refresh token: 7-30 days

Refresh token이란?

refresh token은 일반적으로 의미가 없는 무작위 문자열이며 JWT가 아닙니다. 수명이 길기 때문에 서버 측에 저장하여 폐기할 수 있어야 합니다.

암호학적으로 안전한 RNG로 생성하십시오.

public static string GenerateRefreshToken()
{
    var bytes = new byte[64];
    using var rng = RandomNumberGenerator.Create();
    rng.GetBytes(bytes);
    return Convert.ToBase64String(bytes);
}

Refresh token 저장

각 refresh token을 소유자, 만료 시간 및 폐기 플래그와 함께 저장합니다. 이를 통해 로그아웃하거나 token을 도난당했을 때 무효화할 수 있습니다.

public class RefreshToken
{
    public int Id { get; set; }
    public string Token { get; set; } = default!;
    public int UserId { get; set; }
    public DateTime ExpiresAt { get; set; }
    public bool IsRevoked { get; set; }
}

로그인 시 두 token 모두 발급하기

로그인에 성공하면 수명이 짧은 access token과 새 refresh token을 모두 반환합니다. refresh token은 데이터베이스에 저장합니다.

var access = tokenService.CreateAccessToken(user);
var refresh = new RefreshToken
{
    Token = TokenService.GenerateRefreshToken(),
    UserId = user.Id,
    ExpiresAt = DateTime.UtcNow.AddDays(7)
};
db.RefreshTokens.Add(refresh);
await db.SaveChangesAsync();
return Results.Ok(new { access, refresh = refresh.Token });

Refresh 엔드포인트

전용 /refresh 엔드포인트는 refresh token을 받아 유효한 경우 완전히 새로운 access token을 발급합니다.

app.MapPost("/refresh", async (RefreshDto dto, AppDb db, TokenService tokens) =>
{
    var stored = await db.RefreshTokens
        .SingleOrDefaultAsync(r => r.Token == dto.RefreshToken);

    if (stored is null || stored.IsRevoked ||
        stored.ExpiresAt < DateTime.UtcNow)
        return Results.Unauthorized();

    var user = await db.Users.FindAsync(stored.UserId);
    var access = tokens.CreateAccessToken(user!);
    return Results.Ok(new { access });
});

Refresh token 순환

순환을 적용하면 흐름이 더 안전해집니다. refresh token을 사용할 때마다 이를 폐기하고 새 token을 발급합니다. 그러면 도난당한 후 이미 사용된 token은 더 이상 쓸 수 없습니다.

stored.IsRevoked = true;            // burn the old one
var next = new RefreshToken
{
    Token = TokenService.GenerateRefreshToken(),
    UserId = stored.UserId,
    ExpiresAt = DateTime.UtcNow.AddDays(7)
};
db.RefreshTokens.Add(next);
await db.SaveChangesAsync();

token 재사용 감지

순환을 사용하면 도난을 감지할 수 있습니다. 이미 폐기된 token이 다시 제시되면 보안 침해로 간주하고 사용자의 전체 token 계열을 폐기하십시오.

if (stored.IsRevoked)
{
    // This token was already used - likely stolen.
    await RevokeAllUserTokens(stored.UserId, db);
    return Results.Unauthorized();
}

로그아웃과 폐기

로그아웃하면 현재 refresh token만 폐기합니다. access token은 몇 분 안에 스스로 만료됩니다.

app.MapPost("/logout", async (RefreshDto dto, AppDb db) =>
{
    var stored = await db.RefreshTokens
        .SingleOrDefaultAsync(r => r.Token == dto.RefreshToken);
    if (stored is not null) stored.IsRevoked = true;
    await db.SaveChangesAsync();
    return Results.Ok();
}).RequireAuthorization();

클라이언트에서 token을 저장할 위치

브라우저에서는 refresh token을 HttpOnly, 보안 쿠키에 저장하여 JavaScript가 읽을 수 없게 하는 방식이 가장 안전하며, XSS로 인한 도난을 완화할 수 있습니다.

수명이 짧은 access token은 메모리에 보관할 수 있습니다.

Response.Cookies.Append("refresh", refresh.Token, new CookieOptions
{
    HttpOnly = true,
    Secure = true,
    SameSite = SameSiteMode.Strict,
    Expires = refresh.ExpiresAt
});

만료된 token 정리

refresh token은 계속 쌓입니다. 만료되거나 폐기된 행을 삭제하도록 주기적인 백그라운드 작업(예: 호스팅 서비스)을 실행하십시오.

await db.RefreshTokens
    .Where(r => r.ExpiresAt < DateTime.UtcNow || r.IsRevoked)
    .ExecuteDeleteAsync();

수명 선택

보안과 편의성 사이에서 균형을 잡으십시오.

  • access token: 5~15분 - 유출된 token의 노출을 제한합니다.
  • refresh token: 민감도에 따라 몇 시간에서 몇 주
  • 하루를 초과하는 경우에는 순환을 사용하십시오.
AccessTokenLifetime  = TimeSpan.FromMinutes(15);
RefreshTokenLifetime = TimeSpan.FromDays(7);

빠른 확인

refresh 흐름에 대한 이해도를 확인해 보십시오.

복습

refresh token 흐름을 구현했습니다.

  • 수명이 짧은 access token과 길고 의미가 없으며 서버에 저장된 refresh token을 발급합니다.
  • /refresh 엔드포인트는 유효한 refresh token을 새 access token으로 교환합니다.
  • 순환과 재사용 감지는 도난에 대한 보안을 강화합니다.
  • refresh token은 HttpOnly 쿠키에 저장하고 만료된 행을 정리합니다.

이로써 JWT 인증 강좌를 마칩니다.

자주 묻는 질문

“새로 고침 토큰과 만료” 강의는 무료인가요?

네 — “새로 고침 토큰과 만료” 전체 내용을 이 웹사이트에서 무료로 읽을 수 있습니다. 인터랙티브하게 실습하려면(내장 코드 에디터와 24/7 AI 튜터), CoddyKit PRO로 업그레이드하면 C# Academy 강의 전체를 잠금 해제할 수 있습니다. C# Academy 강의에는 총 4개의 강의가 포함되어 있습니다.

“새로 고침 토큰과 만료”에서 뭘 배우나요?

안전한 토큰 갱신을 구현합니다. 브라우저에서 직접 실행하는 실습 코드로 C# Academy을(를) 배우며, 24/7 AI 튜터가 강의를 진행하면서 질문에 답변해줍니다.

C# Academy을(를) 시작하는 데 경험이 필요한가요?

사전 경험은 필요하지 않습니다. CoddyKit의 C# Academy은(는) 초급자부터 고급 학습자까지를 위해 구성되어 있으므로, 여기서 시작하거나 처음부터 시작할 수 있으며 자신의 속도대로 진행할 수 있습니다. 이것은 4개 중 4번째 강의입니다.

“새로 고침 토큰과 만료” 강의는 얼마나 걸리나요?

대부분의 CoddyKit 강의는 약 5~10분이 소요됩니다. 각 강의는 간결하고 인터랙티브하여 꾸준한 진행이 가능하며, 웹과 앱에서 중단한 부분부터 바로 시작할 수 있습니다.

이 C# Academy 강의에서 코드를 작성하고 실행할 수 있나요?

네. 모든 C# Academy 강의에는 내장 코드 에디터가 포함되어 있으므로, 브라우저에서 바로 실제 코드를 작성하고 실행한 후 즉시 AI 피드백을 받을 수 있습니다 — 로컬 설정이 필요 없습니다.

이 강의의 모든 강의

  1. JWT 구조와 클레임
  2. JWT 전달자 인증 구성
  3. 토큰 발급
  4. 새로 고침 토큰과 만료
← C# Academy(으)로 돌아가기