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 🙏

© 2026 – Pkg Stats / Ryan Hefner

@secondkey/node

v1.1.0

Published

SecureKey Node.js SDK - 다중 채널 2단계 인증 서비스

Readme

@secondkey/node

SecureKey 2FA Node.js SDK — 다중 채널 2단계 인증 서비스

설치

npm install @secondkey/node

빠른 시작

import { TwoFactorClient } from '@secondkey/node';

const client = new TwoFactorClient({
  apiKey: 'your-api-key',
  baseUrl: 'https://securekey.ideacode.co.kr',
});

// SMS OTP 발송
const result = await client.sms.send({
  phone: '01012345678',
  purpose: 'login',
});

// SMS OTP 검증
const verify = await client.sms.verify({
  phone: '01012345678',
  code: '123456',
  purpose: 'login',
});

console.log(verify.verified); // true

지원 채널

| 채널 | 메서드 | 설명 | |------|--------|------| | SMS | client.sms.send() / verify() / status() | SMS OTP 발송 및 검증 | | Email | client.email.send() / verify() / status() | 이메일 OTP 발송 및 검증 | | TOTP | client.totp.setup() / verify() / status() | Google Authenticator 등 TOTP 앱 | | WebAuthn | client.webauthn.registerOptions() / authenticateOptions() | FIDO2/Passkey 생체인증 | | Push | client.push.send() / verify() / waitForApproval() | 푸시 알림 인증 |

SMS OTP

// 발송
const { requestId, expiresAt } = await client.sms.send({
  phone: '01012345678',
  purpose: 'login',
  externalUserId: 'user-123',     // 선택
  serviceName: 'MyApp',           // 선택
});

// 검증
const { verified, verifiedAt } = await client.sms.verify({
  phone: '01012345678',
  code: '123456',
  purpose: 'login',
});

// 상태 확인
const status = await client.sms.status('01012345678');

Email OTP

const { requestId } = await client.email.send({
  email: '[email protected]',
  purpose: 'signup',
});

const { verified } = await client.email.verify({
  email: '[email protected]',
  code: '123456',
  purpose: 'signup',
});

TOTP (시간 기반 OTP)

// 설정 (QR 코드 생성)
const { secret, uri, qrCodeDataUrl, backupCodes } = await client.totp.setup({
  userId: 'user-123',
  accountName: '[email protected]',
});

// 설정 검증 (첫 코드 입력)
await client.totp.verifySetup({
  userId: 'user-123',
  code: '123456',
});

// 이후 로그인 시 검증
const { verified } = await client.totp.verify({
  userId: 'user-123',
  code: '654321',
});

// 백업 코드 재생성
const { backupCodes: newCodes } = await client.totp.regenerateBackupCodes('user-123');

// TOTP 해제
await client.totp.remove('user-123');

WebAuthn (Passkey)

// 등록 시작
const options = await client.webauthn.registerOptions({
  userId: 'user-123',
  userName: '[email protected]',
  userDisplayName: '홍길동',
});

// 브라우저에서 navigator.credentials.create(options) 호출 후
const credential = await client.webauthn.registerVerify({
  userId: 'user-123',
  response: credentialResponse,
  deviceName: 'MacBook Pro',
});

// 인증 시작
const authOptions = await client.webauthn.authenticateOptions({
  userId: 'user-123',
});

// 브라우저에서 navigator.credentials.get(authOptions) 호출 후
const { verified } = await client.webauthn.authenticateVerify({
  userId: 'user-123',
  response: assertionResponse,
});

// 등록된 키 목록 / 삭제
const credentials = await client.webauthn.listCredentials('user-123');
await client.webauthn.deleteCredential('credential-id');

Push 인증

// 기기 등록
const { deviceId } = await client.push.registerDevice({
  userId: 'user-123',
  fcmToken: 'firebase-token',
  deviceName: 'iPhone 15',
  platform: 'ios',
});

// 푸시 인증 요청
const { requestId } = await client.push.send({
  userId: 'user-123',
  title: '로그인 인증 요청',
  body: '새로운 기기에서 로그인을 시도합니다.',
});

// 승인 대기 (폴링)
const { verified, status } = await client.push.waitForApproval(requestId, {
  timeout: 60000,
  interval: 2000,
});

설정 옵션

const client = new TwoFactorClient({
  apiKey: 'your-api-key',           // 필수
  baseUrl: 'https://your-server',   // 기본: http://localhost:8090
  timeout: 30000,                   // 요청 타임아웃 (ms), 기본: 30000
  retries: 3,                       // 재시도 횟수, 기본: 3
  retryDelay: 1000,                 // 재시도 간격 (ms), 기본: 1000
});

에러 처리

import { TwoFactorClient, TwoFactorError } from '@secondkey/node';

try {
  await client.sms.verify({ phone: '01012345678', code: 'wrong' });
} catch (error) {
  if (error instanceof TwoFactorError) {
    console.error(error.code);       // 'INVALID_OTP'
    console.error(error.message);    // '유효하지 않은 인증 코드입니다'
    console.error(error.statusCode); // 400
  }
}

요구 사항

  • Node.js 16 이상
  • 외부 의존성 없음 (제로 디펜던시)

라이선스

MIT — IDEACODE