표준 OAuth/OIDC를 통해 어떤 애플리케이션이든 연결할 수 있습니다.
OpenProof는 프로토콜 경계에서 특정 프로그래밍 언어에 의존하지 않습니다. 제공되는 SDK가 도움이 되는 곳에서는 SDK를 사용하고, 그렇지 않다면 HTTPS와 OAuth 2.0/OpenID Connect를 지원하는 어떤 언어에서도 통합할 수 있습니다.
통합 모델
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부터 시작
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 생성
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 생성
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"]
}'| 종류 | 일반적인 client | Secret |
|---|---|---|
browser | SPA / 브라우저 전용 | 없음 |
native | iOS / Android / desktop | 없음 |
web | Server-rendered / backend 웹 앱 | 한 번만 반환; backend 전용 |
service | Machine-to-machine | 한 번만 반환 |
Authorization Code + PKCE S256
무작위 verifier를 만들고 S256 challenge를 파생한 뒤 무작위 state and nonce. 를 생성하세요. verifier/state/nonce는 해당 로그인 트랜잭션의 수명 동안만 보관하세요.
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 교환
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로 확인합니다.
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();const tokens = await identity.handleCallback(); console.log(tokens.id_token_claims.sub); const profile = await identity.userInfo(tokens.access_token);
기밀 web or service client secret을 사용자에게 전달되는 JavaScript에 포함하지 마세요.
Node.js
framework용으로 검증된 OIDC client를 사용하거나 문서화된 프로토콜에 대해 native fetch() 를 사용하세요. 기밀 credential은 서버 환경/secret store에 보관하세요.
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입니다.
<?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을 유지할 수 있습니다.
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
curl --fail-with-body \ https://auth.example.com/oauth/userinfo \ -H 'Authorization: Bearer ACCESS_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를 등록하세요.
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 --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.
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 |
제품 사용자를 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를 절대 로그에 남기지 마세요.