Genyleap/Docs
OpenProof / 개발

표준 OAuth/OIDC를 통해 어떤 애플리케이션이든 연결할 수 있습니다.

OpenProof는 프로토콜 경계에서 특정 프로그래밍 언어에 의존하지 않습니다. 제공되는 SDK가 도움이 되는 곳에서는 SDK를 사용하고, 그렇지 않다면 HTTPS와 OAuth 2.0/OpenID Connect를 지원하는 어떤 언어에서도 통합할 수 있습니다.

통합 모델

흐름Authorization Code + PKCE
Your app
   ↓ redirect
OpenProof /oauth/authorize
   ↓
authentication / provider / passkey / wallet
   ↓
your callback?code=...&state=...&iss=...
   ↓ code + verifier
OpenProof /oauth/token
   ↓
access_token + id_token + optional refresh_token

제품 통합에는 OAuth/OIDC token을 사용하세요. 안전한 OpenProof session cookie는 OpenProof account/admin origin에 속하므로 제품 domain으로 복사하면 안 됩니다.

Discovery부터 시작

URLauth.example.com 교체
https://auth.example.com/.well-known/openid-configuration
https://auth.example.com/.well-known/jwks.json

재사용 가능한 client가 authorization, token, UserInfo, introspection 및 관련 프로토콜 endpoint를 파악하는 권장 방식은 Discovery입니다.

제품 등록

IAL2 수준의 활성 owner는 다음을 사용할 수 있습니다: /admin/console 또는 administration API.

application 생성

curlowner session 필요
curl --fail-with-body -b owner.cookies \
  https://auth.example.com/admin/applications \
  -H 'Content-Type: application/json' \
  -d '{
    "identifier":"example-web",
    "name":"Example Web",
    "environment":"production"
  }'

client 생성

curlweb client
curl --fail-with-body -b owner.cookies \
  https://auth.example.com/admin/clients \
  -H 'Content-Type: application/json' \
  -d '{
    "application_id":"APPLICATION_ID",
    "name":"Example Web",
    "kind":"web",
    "redirect_uris":["https://app.example.com/oauth/callback"],
    "scopes":["openid","profile","offline_access"]
  }'
종류일반적인 clientSecret
browserSPA / 브라우저 전용없음
nativeiOS / Android / desktop없음
webServer-rendered / backend 웹 앱한 번만 반환; backend 전용
serviceMachine-to-machine한 번만 반환

Authorization Code + PKCE S256

무작위 verifier를 만들고 S256 challenge를 파생한 뒤 무작위 state and nonce. 를 생성하세요. verifier/state/nonce는 해당 로그인 트랜잭션의 수명 동안만 보관하세요.

authorization 요청개념 예시
GET /oauth/authorize?
  response_type=code
  &client_id=CLIENT_ID
  &redirect_uri=https://app.example.com/oauth/callback
  &scope=openid profile offline_access
  &code_challenge=PKCE_CHALLENGE
  &code_challenge_method=S256
  &state=STATE
  &nonce=NONCE

callback에서는 반환된 state and iss 값이 token exchange 전에 트랜잭션/구성된 issuer와 일치하도록 요구하세요.

Token 교환

curlapplication/x-www-form-urlencoded
curl --fail-with-body https://auth.example.com/oauth/token \
  -H 'Content-Type: application/x-www-form-urlencoded' \
  --data-urlencode 'grant_type=authorization_code' \
  --data-urlencode 'client_id=CLIENT_ID' \
  --data-urlencode 'code=AUTHORIZATION_CODE' \
  --data-urlencode 'redirect_uri=https://app.example.com/oauth/callback' \
  --data-urlencode 'code_verifier=PKCE_VERIFIER'

ID token 검증

issuer JWKS로 RS256 서명을 검증하고 최소한 다음 항목을 검증하세요: iss, aud, exp, iat 및 원래 nonce; 또한 nbf, azp and at_hash 존재하는 경우 검증하세요.

JavaScript / 브라우저

repository에는 브라우저 중심 SDK package인 @openproof/identity. 가 포함됩니다. PKCE/state/nonce를 생성하고 callback state/issuer를 검증하며 RS256 ID token을 JWKS로 확인합니다.

javascriptpublic browser client
import { OpenProofIdentity } from "@openproof/identity";

const identity = new OpenProofIdentity({
  issuer: "https://auth.example.com",
  clientId: "CLIENT_ID",
  redirectUri: "https://app.example.com/oauth/callback",
  scopes: ["openid", "profile", "offline_access"]
});

await identity.login();
javascriptcallback
const tokens = await identity.handleCallback();

console.log(tokens.id_token_claims.sub);

const profile =
  await identity.userInfo(tokens.access_token);
브라우저 client에는 client secret이 없습니다.

기밀 web or service client secret을 사용자에게 전달되는 JavaScript에 포함하지 마세요.

Node.js

framework용으로 검증된 OIDC client를 사용하거나 문서화된 프로토콜에 대해 native fetch() 를 사용하세요. 기밀 credential은 서버 환경/secret store에 보관하세요.

javascriptserver-side token exchange
const body = new URLSearchParams({
  grant_type: "authorization_code",
  client_id: process.env.OPENPROOF_CLIENT_ID,
  code,
  redirect_uri: "https://app.example.com/oauth/callback",
  code_verifier: verifier
});

const response = await fetch(
  "https://auth.example.com/oauth/token",
  {
    method: "POST",
    headers: {
      "content-type":
        "application/x-www-form-urlencoded"
    },
    body
  }
);

if (!response.ok) {
  throw new Error(
    `OpenProof token exchange failed: ${response.status}`
  );
}

const tokens = await response.json();

JWKS caching, 서명 검증, claim validation에는 직접 암호 검증 코드를 작성하는 대신 OIDC/JWT library를 사용하세요.

PHP

유지보수되는 어떤 PHP OAuth/OIDC library든 OpenProof를 issuer로 사용할 수 있습니다. 직접 프로토콜은 일반 HTTPS와 form-encoded OAuth입니다.

phptoken exchange
<?php

$payload = http_build_query([
    'grant_type' => 'authorization_code',
    'client_id' => getenv('OPENPROOF_CLIENT_ID'),
    'code' => $_GET['code'],
    'redirect_uri' =>
        'https://app.example.com/oauth/callback',
    'code_verifier' =>
        $_SESSION['openproof_pkce_verifier'],
]);

$curl = curl_init(
    'https://auth.example.com/oauth/token'
);

curl_setopt_array($curl, [
    CURLOPT_POST => true,
    CURLOPT_POSTFIELDS => $payload,
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => [
        'Content-Type: application/x-www-form-urlencoded'
    ],
]);

$body = curl_exec($curl);

if ($body === false) {
    throw new RuntimeException(curl_error($curl));
}

ID token은 유지보수되는 JWT/OIDC package와 issuer JWKS로 검증하세요. RSA/JWK 검증을 임시 방식으로 구현하지 마세요.

C++

repository의 C++26 SDK는 다음 이름으로 export됩니다: openproof.sdk. transport-neutral이므로 기존 Boost.Beast, Qt Network 또는 libcurl stack을 유지할 수 있습니다.

c++SDK 구성
import openproof.sdk;

auto config =
    openproof::sdk::ClientConfig::create(
        "https://auth.example.com",
        "CLIENT_ID",
        "http://127.0.0.1:49152/callback",
        {"openid", "profile", "offline_access"});

openproof::sdk::IdentityClient client{
    std::move(config).value()
};

auto login = client.beginLogin();

std::cout <<
    login->authorizationUrl()
    << '\n';

SDK는 로그인 트랜잭션 생성, authorization-code request 구성, refresh 및 UserInfo용 helper를 제공합니다. 최소 relying-party 예시는 다음 위치에 있습니다: examples/reference-client.

Python, Go, Rust, Java, C# 및 기타 언어

OpenProof 전용 SDK가 필수는 아닙니다. 표준 준수 OAuth/OIDC library를 OpenProof issuer로 구성하세요. 최소 안전 구현은 Discovery → PKCE/state/nonce → authorization redirect → callback checks → token exchange → JWKS signature/claim validation → access-token authorization 순서입니다.

UserInfo 및 refresh

curlUserInfo
curl --fail-with-body \
  https://auth.example.com/oauth/userinfo \
  -H 'Authorization: Bearer ACCESS_TOKEN'
curlrefresh token
curl --fail-with-body \
  https://auth.example.com/oauth/token \
  -H 'Content-Type: application/x-www-form-urlencoded' \
  --data-urlencode 'grant_type=refresh_token' \
  --data-urlencode 'client_id=CLIENT_ID' \
  --data-urlencode 'refresh_token=REFRESH_TOKEN'

Refresh token은 rotation됩니다. 새 token을 원자적으로 저장하고 이전 값은 폐기하세요. Replay protection은 전체 token family를 revoke할 수 있습니다.

API 보호

정확한 audience와 제한된 scope로 resource를 등록하세요.

curlresource 등록
curl --fail-with-body -b owner.cookies \
  https://auth.example.com/admin/resources \
  -H 'Content-Type: application/json' \
  -d '{
    "audience":"https://api.example.com/rides",
    "name":"Ride API",
    "scopes":["rides:read","rides:request"]
  }'

backend는 token 유효성, 정확한 audience, 필요한 scope, 제품 business rule을 모두 확인해 authorization해야 합니다. 유효한 token만으로 충분한 authorization이 되지는 않습니다.

Introspection

curl기밀 backend
curl --fail-with-body \
  https://auth.example.com/oauth/introspect \
  -H 'Content-Type: application/x-www-form-urlencoded' \
  --data-urlencode 'client_id=CONFIDENTIAL_CLIENT_ID' \
  --data-urlencode 'client_secret=CLIENT_SECRET' \
  --data-urlencode 'token=ACCESS_TOKEN'

OpenProof gateway

대안으로 제품 route를 OpenProof 뒤에 배치하고 backend로 proxy하기 전에 정적 route policy에서 role, assurance, scope, audience를 적용할 수 있습니다.

Service 간

다음 service client를 사용하고 허용된 audience/scope를 provision한 뒤 다음 방식으로 access token을 요청하세요: client_credentials.

curlmachine grant
curl --fail-with-body \
  https://auth.example.com/oauth/token \
  -H 'Content-Type: application/x-www-form-urlencoded' \
  --data-urlencode 'grant_type=client_credentials' \
  --data-urlencode 'client_id=CLIENT_ID' \
  --data-urlencode 'client_secret=CLIENT_SECRET' \
  --data-urlencode 'scope=rides:dispatch' \
  --data-urlencode 'resource=https://api.example.com/dispatch'

결과는 access token뿐입니다. refresh token이나 사용자 session은 없습니다.

Account API

account self-service와 verification delivery가 활성화되면 OpenProof는 가입, 검증된 이메일/전화 소유권, 비밀번호 재설정, profile, TOTP, recovery code, passkey를 제공합니다.

용도Endpoint
가입POST /account/signup
이메일 검증POST /account/email/verify
비밀번호 재설정 시작POST /account/password/forgot
비밀번호 재설정 완료POST /account/password/reset
프로필GET/PATCH /account/profile
TOTP 등록POST /account/totp/start/complete
Passkey 로그인POST /auth/passkey/options/verify
연결된 방식GET /account/connections
하나의 canonical identity.

제품 사용자를 Google/GitHub 이메일로 key하지 마세요. 사용자는 동일한 안정적인 OpenProof subject를 유지하면서 여러 로그인 방식을 연결할 수 있습니다.

오류 처리와 secret 위생

오류에는 안정적인 code, client-safe message, request ID가 포함됩니다. 문장이 아니라 code/status로 분기하세요. 401은 누락/유효하지 않은 인증, 403은 권한/assurance 부족, 409는 state conflict, 429는 backoff signal로 처리하세요.

password, TOTP/recovery code, verification secret, authorization code, access/refresh token, 기밀 client secret, cookie, DPoP proof, private key를 절대 로그에 남기지 마세요.