npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

flowauth-oauth2-client

v4.0.0

Published

OAuth2 client SDK for FlowAuth

Readme

FlowAuth OAuth2 SDK

FlowAuth와의 OAuth2 Authorization Code Grant 통합을 위한 간단한 TypeScript/JavaScript SDK입니다.

특징

  • OAuth2 Authorization Code Grant 플로우 지원
  • PKCE (Proof Key for Code Exchange) 지원
  • 자동 토큰 리프래시
  • 토큰 저장 및 관리 (브라우저 sessionStorage/localStorage)
  • TypeScript OAuth2 스코프 enum 제공 (타입 안전한 권한 관리)
  • 브라우저 및 Node.js 환경 지원
  • 강화된 에러 처리 (OAuth2Error 클래스)

환경 요구사항

브라우저 환경

  • ES2018+ 지원 브라우저 (Chrome 64+, Firefox 58+, Safari 12+, Edge 79+)
  • crypto.subtle, fetch, sessionStorage/localStorage 지원

Node.js 환경

  • Node.js 15+ (Web Crypto API 지원)
  • Node.js 18+에서는 fetch가 기본 제공되어 추가 설정 불필요
  • Node.js 14-17에서는 node-fetch 설치 권장:
    npm install node-fetch
  • 토큰 저장: Node.js 환경에서도 토큰 저장이 완전히 지원됩니다
    • 기본값: MemoryStorage (애플리케이션 실행 중 유지)
    • 영구 저장: FileStorage 사용 가능
    • 커스텀 스토리지: TokenStorage 인터페이스 구현

설치

npm을 사용하는 경우

npm install flowauth-oauth2-client

브라우저에서 직접 사용

<script src="https://unpkg.com/flowauth-oauth2-client@latest/dist/index.js"></script>

사용법

TypeScript 환경

import {
  FlowAuthClient,
  OAuth2Scope,
  OAuth2ResponseType,
  OAuth2GrantType,
  OAuth2TokenType
} from "flowauth-oauth2-client";

// 클라이언트 초기화 (자동 토큰 저장 활성화)
const client = new FlowAuthClient({
  server: "https://your-flowauth-server.com",
  clientId: "your-client-id",
  clientSecret: "your-client-secret",
  redirectUri: "https://your-app.com/callback",
  autoRefresh: true, // 자동 토큰 리프래시 활성화 (기본값: true)
});

// 1. State 생성 및 인증 URL 생성 (타입 안전한 enum 사용)
const state = await FlowAuthClient.generateState();

// Authorization Code Flow (권장)
const authUrl = client.createAuthorizeUrl(
  [OAuth2Scope.OPENID, OAuth2Scope.PROFILE, OAuth2Scope.EMAIL],
  state,
  undefined,
  undefined,
  OAuth2ResponseType.CODE
);

console.log("인증 URL:", authUrl);
// 사용자를 authUrl로 리다이렉트

// 2. 콜백에서 코드 교환 (State 검증 및 토큰 자동 저장)
try {
  // 콜백 URL에서 파라미터 추출
  const urlParams = new URLSearchParams(window.location.search);
  const receivedState = urlParams.get("state");
  const receivedCode = urlParams.get("code");

  // State 검증 (CSRF 방지)

순수 JavaScript 환경

SDK는 순수 JavaScript 환경에서도 완전히 지원됩니다. 런타임 상수 객체들을 제공하여 타입 정의 없이도 안전하게 사용할 수 있습니다.

const {
  FlowAuthClient,
  OAuth2ResponseTypes,
  OAuth2GrantTypes,
  OAuth2TokenTypes,
  OAuth2Scope,
  OAUTH2_CONSTANTS,
} = require("flowauth-oauth2-client");

// 클라이언트 초기화
const client = new FlowAuthClient({
  server: "https://your-flowauth-server.com",
  clientId: "your-client-id",
  clientSecret: "your-client-secret",
  redirectUri: "https://your-app.com/callback",
});

// 런타임 상수 사용
console.log("지원되는 응답 타입들:", OAuth2ResponseTypes);
// 출력: { CODE: "code" }

console.log("지원되는 Grant 타입들:", OAuth2GrantTypes);
// 출력: { AUTHORIZATION_CODE: "authorization_code", REFRESH_TOKEN: "refresh_token", ... }

// Authorization Code Flow
const authUrl = client.createAuthorizeUrl(
  [OAuth2Scope.OPENID, OAuth2Scope.PROFILE],
  state,
  pkce,
);

// 콜백 처리
function handleCallback(callbackParams) {
  // Authorization Code 처리
  if (callbackParams.code) {
    client
      .exchangeCode(callbackParams.code)
      .then(tokens => console.log("토큰 받음:", tokens))
      .catch(error => console.error("토큰 교환 실패:", error));
  }

  // 에러 처리
  if (callbackParams.error) {
    console.error("OAuth2 에러:", callbackParams.error);
  }
}

// 응답 타입 검증
function isValidResponseType(responseType) {
  return OAUTH2_CONSTANTS.SUPPORTED_RESPONSE_TYPES.includes(responseType);
}

console.log(isValidResponseType(OAuth2ResponseTypes.CODE)); // true
console.log(isValidResponseType("invalid_type")); // false

기본 사용법

// 클라이언트 초기화
const client = new FlowAuthClient({
  server: "https://your-flowauth-server.com",
  clientId: "your-client-id",
  clientSecret: "your-client-secret",
  redirectUri: "https://your-app.com/callback",
});

// 1. State 생성 및 인증 URL 생성
const state = await FlowAuthClient.generateState();
// 권장 스코프 사용
const authUrl = client.createAuthorizeUrl(
  [OAuth2Scope.OPENID, OAuth2Scope.PROFILE],
  state,
);

// 사용자를 authUrl로 리다이렉트
window.location.href = authUrl;

// 2. 콜백에서 코드 교환 (State 검증 및 토큰 자동 저장)
try {
  // 콜백 URL에서 파라미터 추출
  const urlParams = new URLSearchParams(window.location.search);
  const receivedState = urlParams.get("state");
  const receivedCode = urlParams.get("code");

  // State 검증 (CSRF 방지)
  if (receivedState !== state) {
    throw new Error("State mismatch - possible CSRF attack");
  }

  const tokens = await client.exchangeCode(receivedCode);
  console.log("Tokens:", tokens);
} catch (error) {
  console.error("Authentication failed:", error.message);
}

// 3. 저장된 토큰으로 사용자 정보 조회 (자동 리프래시)
const userInfo = await client.getUserInfo();
console.log("User Info:", userInfo);

// 4. 토큰 검증
const isValid = await client.validateToken();
console.log("Token is valid:", isValid);

// 5. 로그아웃 (저장된 토큰 제거)
client.logout();

PKCE 및 State 사용 예제

// 방법 1: 개별 생성 및 수동 관리
const pkce = await FlowAuthClient.generatePKCE();
const state = await FlowAuthClient.generateState();
const authUrl = client.createAuthorizeUrl(
  [OAuth2Scope.OPENID, OAuth2Scope.PROFILE],
  state,
  pkce,
);
const tokens = await client.exchangeCode(
  "authorization-code",
  pkce.codeVerifier,
);

// 방법 2: PKCE와 State를 함께 생성 (편의 메소드)
const authParams = await FlowAuthClient.generateSecureAuthParams();
const authUrl = client.createAuthorizeUrl(
  [OAuth2Scope.OPENID, OAuth2Scope.PROFILE],
  authParams.state,
  authParams.pkce,
);
const tokens = await client.exchangeCode(
  "authorization-code",
  authParams.pkce.codeVerifier,
);

// 방법 3: 완전 자동화된 보안 인증 URL 생성 (가장 간단)
const { authUrl, codeVerifier, state } = await client.createSecureAuthorizeUrl([
  OAuth2Scope.OPENID,
  OAuth2Scope.PROFILE,
  OAuth2Scope.EMAIL,
]);
// authUrl로 사용자를 리다이렉트하고, codeVerifier와 state를 세션에 저장
// 콜백에서:
const tokens = await client.exchangeCode("authorization-code", codeVerifier);

스코프 활용 예제

SDK는 TypeScript enum을 통해 타입 안전한 스코프 관리를 제공합니다:

const {
  FlowAuthClient,
  OAuth2Scope,
  DEFAULT_SCOPES,
} = require("flowauth-oauth2-client");

const client = new FlowAuthClient({
  server: "https://your-flowauth-server.com",
  clientId: "your-client-id",
  clientSecret: "your-client-secret",
  redirectUri: "https://your-app.com/callback",
});

// 1. 기본 스코프 사용 (가장 일반적인 경우)
const authUrl = client.createAuthorizeUrl(DEFAULT_SCOPES);
console.log("기본 권한으로 인증:", authUrl);

// 2. 이메일 권한 추가 요청
const emailAuthUrl = client.createAuthorizeUrl([
  OAuth2Scope.OPENID,
  OAuth2Scope.PROFILE,
  OAuth2Scope.EMAIL,
]);
console.log("이메일 정보 접근 인증:", emailAuthUrl);

Node.js 스토리지 사용 예제

const {
  FlowAuthClient,
  MemoryStorage,
  FileStorage,
  OAuth2Scope,
} = require("flowauth-oauth2-client");

// 1. 메모리 스토리지 사용 (기본값, 애플리케이션 실행 중에만 유지)
const client = new FlowAuthClient({
  server: "https://your-flowauth-server.com",
  clientId: "your-client-id",
  clientSecret: "your-client-secret",
  redirectUri: "https://your-app.com/callback",
  // storage: new MemoryStorage() // 기본값이므로 생략 가능
});

// 2. 파일 기반 스토리지 사용 (영구 저장)
const fileStorage = new FileStorage("./tokens.json");
const clientWithFileStorage = new FlowAuthClient({
  server: "https://your-flowauth-server.com",
  clientId: "your-client-id",
  clientSecret: "your-client-secret",
  redirectUri: "https://your-app.com/callback",
  storage: fileStorage,
});

// 3. 커스텀 스토리지 구현
class RedisStorage {
  constructor(redisClient) {
    this.redis = redisClient;
  }

  async getItem(key) {
    return await this.redis.get(key);
  }

  async setItem(key, value) {
    await this.redis.set(key, value);
  }

  async removeItem(key) {
    await this.redis.del(key);
  }

  async clear() {
    // Redis에서 모든 키 삭제 로직
  }
}

const redisStorage = new RedisStorage(redisClient);
const clientWithRedis = new FlowAuthClient({
  server: "https://your-flowauth-server.com",
  clientId: "your-client-id",
  clientSecret: "your-client-secret",
  redirectUri: "https://your-app.com/callback",
  storage: redisStorage,
});

사용자 프로필 애플리케이션

const { FlowAuthClient, OAuth2Scope } = require("flowauth-oauth2-client");

class UserProfileApp {
  constructor() {
    this.client = new FlowAuthClient({
      server: "https://flowauth.example.com",
      clientId: "profile-app",
      clientSecret: "secret",
      redirectUri: "https://profile-app.com/callback",
    });
  }

  // 로그인 시작
  async startLogin() {
    const { authUrl, codeVerifier, state } =
      await this.client.createSecureAuthorizeUrl([
        OAuth2Scope.OPENID,
        OAuth2Scope.PROFILE,
        OAuth2Scope.EMAIL,
      ]);

    // 세션에 PKCE 정보 저장
    sessionStorage.setItem("oauth_code_verifier", codeVerifier);
    sessionStorage.setItem("oauth_state", state);

    // 사용자를 인증 페이지로 리다이렉트
    window.location.href = authUrl;
  }

  // 콜백 처리
  async handleCallback() {
    const urlParams = new URLSearchParams(window.location.search);
    const code = urlParams.get("code");
    const receivedState = urlParams.get("state");

    const savedState = sessionStorage.getItem("oauth_state");
    const codeVerifier = sessionStorage.getItem("oauth_code_verifier");

    if (receivedState !== savedState) {
      throw new Error("State 검증 실패");
    }

    // 토큰 교환 및 저장
    await this.client.exchangeCode(code, codeVerifier);

    // 세션 정리
    sessionStorage.removeItem("oauth_code_verifier");
    sessionStorage.removeItem("oauth_state");

    // 메인 페이지로 리다이렉트
    window.location.href = "/profile";
  }

  // 사용자 정보 표시
  async displayUserProfile() {
    try {
      const userInfo = await this.client.getUserInfo();
      console.log("사용자 정보:", userInfo);

      // 프로필 UI 업데이트
      this.updateProfileUI(userInfo);
    } catch (error) {
      console.error("프로필 로드 실패:", error);
      // 로그인 페이지로 리다이렉트
      this.startLogin();
    }
  }

  updateProfileUI(userInfo) {
    // 실제 애플리케이션에서는 DOM 업데이트
    console.log(`환영합니다, ${userInfo.username || userInfo.email}!`);
  }
}

권한 기반 UI 렌더링

const { FlowAuthClient, OAuth2Scope } = require("flowauth-oauth2-client");

class PermissionBasedUI {
  constructor(client) {
    this.client = client;
  }

  // 현재 사용자의 권한에 따른 UI 렌더링
  async renderUI() {
    const tokenInfo = this.client.getTokenInfo();
    if (!tokenInfo) {
      this.renderLoginButton();
      return;
    }

    const scopes = tokenInfo.scope ? tokenInfo.scope.split(" ") : [];

    // 이메일 정보 표시 UI
    if (scopes.includes(OAuth2Scope.EMAIL)) {
      this.renderEmailSection();
    }

    // 기본 사용자 정보 UI
    if (scopes.includes(OAuth2Scope.PROFILE)) {
      this.renderUserProfile();
    }
  }

  renderLoginButton() {
    console.log("로그인 버튼 표시");
    // 실제로는 DOM 조작
  }

  renderEmailSection() {
    console.log("이메일 정보 섹션 표시");
  }

  renderUserProfile() {
    console.log("사용자 프로필 섹션 표시");
  }

  // 추가 권한 요청 UI
  renderScopeRequest() {
    console.log("추가 권한 요청:");
    const additionalScopes = [OAuth2Scope.EMAIL];

    console.log("- 이메일 주소 접근 권한");

    // 추가 권한으로 재인증 링크 생성
    const authUrl = this.client.createAuthorizeUrl([
      OAuth2Scope.OPENID,
      OAuth2Scope.PROFILE,
      OAuth2Scope.EMAIL,
    ]);
    console.log("추가 권한 요청 URL:", authUrl);
  }
}

// 사용 예시
const client = new FlowAuthClient({
  /* 설정 */
});
const ui = new PermissionBasedUI(client);
ui.renderUI();

고급 사용법

// 커스텀 스토리지 사용 (Node.js 환경 등)
const client = new FlowAuthClient({
  server: "https://your-server.com",
  clientId: "client-id",
  clientSecret: "client-secret",
  redirectUri: "https://your-app.com/callback",
  storage: customStorage, // 커스텀 Storage 구현
  autoRefresh: false, // 수동 리프래시
});

// 수동 토큰 관리
const tokens = await client.exchangeCode("code");
const userInfo = await client.getUserInfo(tokens.access_token);

// 수동 리프래시
const newTokens = await client.refreshToken(tokens.refresh_token);

// 토큰 정보 조회
const tokenInfo = client.getTokenInfo();
console.log("Current tokens:", tokenInfo);

배포

npm에 패키지를 배포하려면:

npm run build
npm publish

빌드 후 dist 폴더에 컴파일된 파일이 생성됩니다.

테스트

테스트를 실행하려면:

npm run test:run

또는 개발 중 감시 모드로:

npm test

API 문서

OAuth2 스코프

SDK는 다음과 같은 OAuth2 스코프들을 enum으로 제공합니다:

enum OAuth2Scope {
  OPENID = "openid", // OpenID Connect 인증을 위한 기본 스코프
  PROFILE = "profile", // 사용자 프로필 정보 (이름, 생년월일, 지역, 사진 등) 접근
  EMAIL = "email", // 사용자 이메일 주소 읽기
}

기본 스코프:

const DEFAULT_SCOPES = [OAuth2Scope.OPENID, OAuth2Scope.PROFILE];

FlowAuthClient 클래스

생성자

new FlowAuthClient(config: OAuth2ClientConfig)

파라미터:

  • server: FlowAuth 서버 URL
  • clientId: OAuth2 클라이언트 ID
  • clientSecret: OAuth2 클라이언트 시크릿
  • redirectUri: 인증 후 리다이렉트 URI
  • storage?: 커스텀 스토리지 구현 (기본값: 브라우저 sessionStorage 또는 Node.js MemoryStorage)
  • autoRefresh?: 자동 토큰 리프래시 활성화 (기본값: true)

메소드

  • createAuthorizeUrl(scopes?, state?, pkce?, nonce?, responseType?): 인증 URL 생성 (기본값: [OAuth2Scope.PROFILE])
  • createSecureAuthorizeUrl(scopes?, responseType?): PKCE와 State를 자동 생성하여 보안 인증 URL 생성 (기본값: [OAuth2Scope.PROFILE])
  • exchangeCode(code, codeVerifier?): Authorization Code를 토큰으로 교환
  • refreshToken(refreshToken?): 토큰 리프래시 (저장된 토큰 자동 사용)
  • validateToken(accessToken?): 토큰 유효성 검증
  • getStoredAccessToken(): 저장된 액세스 토큰 조회
  • getTokenInfo(): 현재 토큰 정보 조회
  • logout(): 저장된 토큰 제거

정적 메소드

  • FlowAuthClient.generatePKCE(): PKCE 챌린지 생성
  • FlowAuthClient.generateState(): OAuth2 State 파라미터 생성
  • FlowAuthClient.generateSecureAuthParams(): PKCE와 State를 함께 생성

스토리지 클래스

MemoryStorage

메모리 기반 스토리지로 애플리케이션 실행 중에만 데이터를 유지합니다.

class MemoryStorage implements TokenStorage {
  getItem(key: string): string | null;
  setItem(key: string, value: string): void;
  removeItem(key: string): void;
  clear(): void;
}

FileStorage

JSON 파일에 데이터를 영구 저장하는 스토리지입니다.

class FileStorage implements TokenStorage {
  constructor(filePath?: string);
  getItem(key: string): string | null;
  setItem(key: string, value: string): void;
  removeItem(key: string): void;
  clear(): void;
}

파라미터:

  • filePath: 토큰을 저장할 파일 경로 (기본값: "./.flowauth-tokens.json")

TokenStorage 인터페이스

커스텀 스토리지를 구현하기 위한 인터페이스입니다.

interface TokenStorage {
  getItem(key: string): string | null;
  setItem(key: string, value: string): void;
  removeItem(key: string): void;
  clear?(): void;
}

에러 처리

SDK는 OAuth2Error 클래스를 사용하여 OAuth2 관련 에러를 제공합니다:

import { OAuth2Error } from "flowauth-oauth2-client";
// 또는 CommonJS: const { OAuth2Error } = require("flowauth-oauth2-client");

try {
  const tokens = await client.exchangeCode(code);
} catch (error) {
  if (error instanceof OAuth2Error) {
    console.log("OAuth2 Error:", error.status, error.code, error.message);
  }
}

자세한 API 문서와 OAuth2/OIDC 플로우 설명은 가이드 문서를 참조하세요.

라이선스

이 SDK는 FlowAuth 프로젝트의 일부입니다. FlowAuth 프로젝트와 동일한 MIT 라이선스를 사용합니다.