백엔드 없이 만료되는 링크를 만든 방법 (React + TypeScript Only)
Source: Dev.to
Introduction
대부분의 “만료 링크” 도구는 같은 방식으로 동작합니다: 링크를 생성하고, 목적지와 만료 시간을 데이터베이스에 저장한 뒤, 클릭할 때마다 데이터베이스를 확인하고 그에 따라 리다이렉트하거나 차단합니다.
이 접근 방식은 백엔드, 데이터베이스, 서버 비용, 그리고 보안 위험을 필요로 합니다.
저는 React + TypeScript만 사용하고, Vercel에 배포하며 Node.js도, 데이터베이스도, 백엔드도 전혀 없는 제약이 있었습니다.
해결책은 링크 데이터를 URL 자체에 인코딩하는 것이었습니다.
How It Works
사용자가 만료 링크를 만들면 앱은 다음을 수행합니다:
- 목적지 URL을 가져옵니다.
- 만료 타임스탬프(Unix ms)를 가져옵니다.
- 두 값을 JSON 객체로 결합합니다.
btoa()(Base64)로 JSON을 인코딩합니다.- 인코딩된 페이로드를 URL 파라미터로 추가합니다.
- TinyURL API를 이용해 전체 URL을 단축합니다.
// Create payload
const payload = {
url: destinationUrl,
exp: expiryTimestamp
};
const encoded = btoa(JSON.stringify(payload));
const longUrl = `https://onetimelink.vercel.app/r?d=${encoded}`;
// Shorten (TinyURL)
const shortUrl = await shortenWithTinyURL(longUrl);
누군가 짧은 링크를 방문하면 TinyURL이 이를 다시 긴 URL로 확장합니다. React 앱은 클라이언트‑사이드에서 파라미터를 디코드합니다:
const params = new URLSearchParams(window.location.search);
const encoded = params.get('d');
if (!encoded) {
// Invalid link
return;
}
try {
const payload = JSON.parse(atob(encoded));
const now = Date.now();
if (now > payload.exp) {
// Expired — show expiration screen
setExpired(true);
} else {
// Valid — redirect
window.location.href = payload.url;
}
} catch {
// Malformed link
setInvalid(true);
}
데이터베이스 조회도, 서버 호출도, 어디에도 저장된 데이터도 없습니다. 링크 자체에 만료 정보가 담겨 있으며, 리다이렉트 여부 판단은 전부 브라우저에서 이루어집니다.
Benefits
- 스토리지 제로 → 보안 위험 제로. 데이터는 공유된 URL에만 존재합니다.
- 서버 비용 없음. 제품은 Vercel 무료 티어에서 실행되며, 링크 방문 시 서버‑사이드 연산이 전혀 발생하지 않습니다.
- 오프라인에서도 부분적으로 동작. URL이 캐시돼 있다면, 만료 검사는 단순히 타임스탬프 비교이므로 여전히 작동합니다.
Limitations
| Limitation | Details |
|---|---|
| URL 길이 | JSON 객체를 Base64‑인코딩하면 문자 수가 늘어납니다. TinyURL이 링크를 짧게 만들어 주지만, 중간 URL은 길어질 수 있습니다. |
| 서버‑사이드 검증 부재 | 사용자가 페이로드를 디코드하고, 만료 타임스탬프를 수정한 뒤 다시 인코드해 “만료되지 않는” 링크를 만들 수 있습니다. 캐주얼한 사용 사례에는 적합하지만, 적대적인 상황에는 부적합합니다. |
| 분석 기능 없음 | 서버‑사이드 저장소가 없으므로 클릭 수를 추적하거나 대시보드를 볼 수 없습니다. |
| 조기 폐기 불가 | 한 번 생성되면 링크는 타임스탬프가 지나야만 만료되며, 조기에 삭제할 방법이 없습니다. |
Ideal Use Cases
- 임시 로그인 자격 증명을 전달할 때.
- 리뷰 기간 동안의 스테이징 환경 링크.
- 자연스러운 종료 날짜가 있는 비공개 문서.
이러한 시나리오에서는 제한 사항이 허용됩니다: 클라이언트가 한 번 클릭해 필요한 정보를 얻고, 창이 닫히면 링크가 사라집니다.
분석, 다중 클릭 추적, 조기 폐기 등이 필요하다면 적절한 백엔드가 필요합니다.
Tech Stack
- React + TypeScript
- Vite for bundling
- Vercel (free tier) for deployment
- TinyURL API (free tier, no authentication)
- Built‑in browser functions
btoa()/atob()for encoding
Total server infrastructure cost: $0.
Conclusion
백엔드의 오버헤드 없이 민감한 링크를 일시적으로 공유해야 할 때, 만료 데이터를 URL에 인코딩하는 방법은 실현 가능한, 비용이 전혀 들지 않는 대안이 됩니다. 실제 구현은 – 무료로 사용 가능하고, 계정도 필요 없습니다.
자세한 아키텍처와 제품 방향은 OneTimeLink 블로그에서 확인할 수 있습니다.