Scalekit & Astro
Scalekit은 B2B 및 AI 애플리케이션을 위해 구축된 인증 플랫폼입니다. 소셜 로그인, 엔터프라이즈 SSO, 매직 링크 등을 제공합니다 — 전체 OAuth 2.0 / OIDC 흐름을 관리하므로 로그인 UI를 구축할 필요 없이 토큰과 사용자 프로필을 얻을 수 있습니다. 단일 Scalekit 환경이 여러 애플리케이션(예: app.yourcompany.com 및 docs.yourcompany.com)을 지원하므로, 사용자가 한 번 인증하면 모든 속성에서 동일한 세션을 공유합니다.
Astro에서 Scalekit 초기화
섹션 제목: “Astro에서 Scalekit 초기화”전제조건
섹션 제목: “전제조건”- Scalekit 계정과 환경이 필요합니다. 없다면 scalekit.com에 무료로 가입하여 새 환경을 생성할 수 있습니다.
- 요청 시 렌더링을 위해
output: 'server'가 활성화된 Astro 프로젝트가 필요합니다. - Scalekit 환경의 자격 증명이 필요합니다. Scalekit 대시보드 Settings > API Credentials 섹션에서 찾을 수 있습니다.
SCALEKIT_ENVIRONMENT_URL: Scalekit 환경의 URL입니다.SCALEKIT_CLIENT_ID: Scalekit 클라이언트 ID입니다.SCALEKIT_CLIENT_SECRET: Scalekit 클라이언트 비밀입니다.SCALEKIT_REDIRECT_URI: 로그인 후 Scalekit가 리디렉션할 콜백 URL입니다 (예:http://localhost:4321/api/auth/callback). Scalekit 대시보드의 Settings > Redirects에서 등록하세요.
Scalekit 자격 증명 추가
섹션 제목: “Scalekit 자격 증명 추가”Astro 프로젝트에 Scalekit 자격 증명을 추가하려면 .env 파일에 다음을 추가하세요.
SCALEKIT_ENVIRONMENT_URL=YOUR_SCALEKIT_ENVIRONMENT_URLSCALEKIT_CLIENT_ID=YOUR_SCALEKIT_CLIENT_IDSCALEKIT_CLIENT_SECRET=YOUR_SCALEKIT_CLIENT_SECRETSCALEKIT_REDIRECT_URI=http://localhost:4321/api/auth/callback이제 이러한 환경 변수를 프로젝트에서 사용할 수 있습니다.
환경 변수에 IntelliSense를 사용하려면 src/ 디렉터리의 env.d.ts 파일을 수정하거나 생성하여 다음을 추가하세요.
/// <reference types="astro/client" />
interface ImportMetaEnv { readonly SCALEKIT_ENVIRONMENT_URL: string; readonly SCALEKIT_CLIENT_ID: string; readonly SCALEKIT_CLIENT_SECRET: string; readonly SCALEKIT_REDIRECT_URI: string;}
interface ImportMeta { readonly env: ImportMetaEnv;}
declare namespace App { interface Locals { user?: { sub: string; email?: string; name?: string; }; }}.env 파일에 대해 자세히 알아보세요.
프로젝트에 다음 파일이 포함되어야 합니다.
디렉터리src/
- env.d.ts
- .env
- astro.config.mjs
- package.json
종속성 설치
섹션 제목: “종속성 설치”Scalekit에 연결하려면 프로젝트에 @scalekit-sdk/node를 설치하세요.
npm install @scalekit-sdk/nodepnpm add @scalekit-sdk/nodeyarn add @scalekit-sdk/node그 다음, src/ 디렉터리에 lib 폴더를 만들고 Scalekit 클라이언트 파일을 추가하세요.
import { ScalekitClient } from "@scalekit-sdk/node";
export const scalekit = new ScalekitClient( import.meta.env.SCALEKIT_ENVIRONMENT_URL, import.meta.env.SCALEKIT_CLIENT_ID, import.meta.env.SCALEKIT_CLIENT_SECRET,);
export const REDIRECT_URI = import.meta.env.SCALEKIT_REDIRECT_URI ?? "http://localhost:4321/api/auth/callback";프로젝트에 다음 파일이 포함되어야 합니다.
디렉터리src/
디렉터리lib/
- scalekit.ts
- env.d.ts
- .env
- package.json
Scalekit로 인증 추가
섹션 제목: “Scalekit로 인증 추가”Scalekit은 표준 OAuth 2.0 / OIDC 리디렉션 흐름을 통해 인증을 처리합니다. 앱에서 사용자를 Scalekit으로 보내면, 사용자가 로그인하고 Scalekit이 권한 코드와 함께 콜백 URL로 리디렉션합니다. 그 다음 해당 권한 코드를 토큰으로 교환합니다. 이 가이드에서는 클라이언트 비밀과 함께 권한 코드 흐름을 사용하며, 이는 서버 측 렌더링 애플리케이션에 적합합니다.
클라이언트 비밀을 사용하지 않으려면 Scalekit이 PKCE 흐름도 지원합니다. Scalekit 개발자 문서 사이트는 SDK 없이 전체 PKCE 구현을 보여주는 오픈소스 Astro 프로젝트입니다.
인증 서버 엔드포인트 생성
섹션 제목: “인증 서버 엔드포인트 생성”프로젝트에 인증을 추가하려면 세 개의 서버 엔드포인트를 생성해야 합니다.
GET /api/auth/login: 사용자를 Scalekit에서 로그인하도록 리디렉션합니다.GET /api/auth/callback: 권한 코드를 토큰으로 교환하고 세션 쿠키를 설정합니다.GET /api/auth/logout: 세션 쿠키를 지우고 Scalekit 세션을 종료합니다.
프로젝트의 src/pages/api/auth/ 디렉터리에 이러한 엔드포인트를 생성하세요. 프로젝트에 다음 새 파일이 포함되어야 합니다.
디렉터리src/
디렉터리lib/
- scalekit.ts
디렉터리pages/
디렉터리api/
디렉터리auth/
- login.ts
- callback.ts
- logout.ts
- env.d.ts
- .env
- astro.config.mjs
- package.json
login.ts은 권한 URL을 생성하고 사용자를 Scalekit에서 로그인하도록 리디렉션합니다.
import type { APIRoute } from "astro";import { scalekit, REDIRECT_URI } from "../../../lib/scalekit";
export const GET: APIRoute = async () => { const url = scalekit.getAuthorizationUrl(REDIRECT_URI, { scopes: ["openid", "profile", "email", "offline_access"], }); return Response.redirect(url);};callback.ts는 Scalekit에서 권한 코드를 수신하고, 토큰으로 교환한 후 HttpOnly 쿠키에 저장합니다.
import type { APIRoute } from "astro";import { scalekit, REDIRECT_URI } from "../../../lib/scalekit";
export const GET: APIRoute = async ({ request, cookies }) => { const url = new URL(request.url); const code = url.searchParams.get("code");
if (!code) { return Response.redirect(new URL("/", request.url).origin); }
const { user, idToken, accessToken, refreshToken } = await scalekit.authenticateWithCode(code, REDIRECT_URI);
const secure = url.protocol === "https:"; const cookieOptions = { httpOnly: true, path: "/", sameSite: "lax" as const, secure };
cookies.set("sk-id-token", idToken, cookieOptions); cookies.set("sk-access-token", accessToken, cookieOptions); cookies.set("sk-refresh-token", refreshToken, cookieOptions);
return Response.redirect(new URL("/", request.url).origin);};logout.ts는 세션 쿠키를 지우고 Scalekit 로그아웃 엔드포인트로 리디렉션하여 Scalekit 세션을 종료합니다.
import type { APIRoute } from "astro";import { scalekit } from "../../../lib/scalekit";
export const GET: APIRoute = async ({ request, cookies }) => { const idToken = cookies.get("sk-id-token")?.value;
cookies.delete("sk-id-token", { path: "/" }); cookies.delete("sk-access-token", { path: "/" }); cookies.delete("sk-refresh-token", { path: "/" });
const logoutUrl = scalekit.getLogoutUrl({ idTokenHint: idToken, postLogoutRedirectUri: new URL("/", request.url).origin, });
return Response.redirect(logoutUrl);};getLogoutUrl()에 전달된 postLogoutRedirectUri는 Scalekit 대시보드에서 허용된 post-logout 리디렉션 URI로 등록되어야 합니다. 그렇지 않으면 Scalekit이 로그아웃 요청을 거부합니다.
세션 미들웨어 추가
섹션 제목: “세션 미들웨어 추가”모든 요청에서 액세스 토큰을 검증하고 Astro.locals.user에 인증된 사용자 프로필을 채우려면 src/middleware.ts 파일을 생성하세요. 액세스 토큰이 만료되면 미들웨어가 리프레시 토큰을 사용하여 자동으로 갱신합니다.
import { defineMiddleware } from "astro:middleware";import type { IdTokenClaim } from "@scalekit-sdk/node";import { scalekit } from "./lib/scalekit";
export const onRequest = defineMiddleware(async (context, next) => { const accessToken = context.cookies.get("sk-access-token")?.value;
if (accessToken) { try { const claims = await scalekit.validateToken<IdTokenClaim>(accessToken); context.locals.user = { sub: claims.sub, email: claims.email, name: claims.name, }; } catch { // 액세스 토큰이 유효하지 않거나 만료됨 — 갱신 시도 const refreshToken = context.cookies.get("sk-refresh-token")?.value; if (refreshToken) { try { const { accessToken: newToken } = await scalekit.refreshAccessToken(refreshToken);
const secure = new URL(context.request.url).protocol === "https:"; context.cookies.set("sk-access-token", newToken, { httpOnly: true, path: "/", sameSite: "lax", secure, });
const claims = await scalekit.validateToken<IdTokenClaim>(newToken); context.locals.user = { sub: claims.sub, email: claims.email, name: claims.name, }; } catch { // 갱신 실패 — 세션 쿠키 지우기 context.cookies.delete("sk-id-token", { path: "/" }); context.cookies.delete("sk-access-token", { path: "/" }); context.cookies.delete("sk-refresh-token", { path: "/" }); } } } }
return next();});인증된 페이지 생성
섹션 제목: “인증된 페이지 생성”이제 미들웨어가 Astro.locals.user를 채우므로, 인증 상태에 따라 다른 콘텐츠를 표시하는 페이지를 생성할 수 있습니다.
dashboard.astro는 인증된 사용자만 액세스할 수 있는 페이지입니다. 미들웨어에서 설정된 Astro.locals에서 사용자를 읽고, 사용자가 로그인하지 않았으면 홈 페이지로 리디렉션합니다.
---import Layout from "../layouts/Layout.astro";
const user = Astro.locals.user;
if (!user) { return Astro.redirect("/");}---
<Layout title="Dashboard"> <h1>Welcome, {user.name ?? user.email}</h1> <p>You are signed in.</p> <a href="/api/auth/logout">Sign out</a></Layout>커뮤니티 리소스
섹션 제목: “커뮤니티 리소스”- Scalekit Node.js SDK 문서
- Scalekit 인증이 포함된 Astro 블로그 튜토리얼 (Authorization Code flow)
- Scalekit 개발자 문서 사이트 소스 (PKCE flow, no SDK)