ํ ๋ง
๐ ์น ํตํฉ ํธ๋ โ
Next.js ยท Rails ยท Express ๋ฑ ์๋ฒ ์ฌ์ด๋ ์น ์ฑ์์ logi ๋ฅผ ํตํฉํ๋ ๊ฐ์ฅ ๋น ๋ฅธ ๊ธธ.
์ด ํธ๋์ด ๋ง๋์?
- โ ๋ง์: ๋ฐฑ์๋๊ฐ ์๊ณ , ์ฌ์ฉ์๊ฐ ๋ธ๋ผ์ฐ์ ์์ ์ ์ํ๋ ์น ์๋น์ค
- โ ๋ชจ๋ฐ์ผ ์ฑ ์ด๋ผ๋ฉด โ ๐ฑ ๋ชจ๋ฐ์ผ ์ฑ ํตํฉ ํธ๋
- โ ์์ SPA (๋ฐฑ์๋ ์์) ์ด๋ผ๋ฉด โ Public Client + PKCE. public-clients ์ฐธ๊ณ
- โ ๋ฐ์คํฌํฑ SSO (Apple / Google ID ํ ํฐ ์ง์์ ) ์ด๋ผ๋ฉด โ Web SSO (๋ฐ์คํฌํฑ)
ํต์ฌ ์ฝ์ 4์ค โ
- Confidential client +
client_secret์๋ฒ ๋ณด๊ด. ์ ๋ ๋ธ๋ผ์ฐ์ ๋ฒ๋ค์ ๋ ธ์ถ ๊ธ์ง. - redirect_uri ๋
https://...๋๋http://localhostโ ์๋ฒ ์ฝ๋ฐฑ ๋ผ์ฐํธ ๊ฒฝ๋ก. - state + nonce ๊ฒ์ฆ + HttpOnly ยท Secure ์ฟ ํค ๋ก ์ธ์ ๋ฐ๊ธ.
- ์ฑ RP ์ ์น RP ๋ ๋ถ๋ฆฌ โ ์์ธํ: ๊ณตํต/Public Clients ยท Surface ๋ณ RP ๋ถ๋ฆฌ
Step 1 ยท ์ฑ ๋ฑ๋ก โ
SPA / ํด๋ผ์ด์ธํธ ์ฌ์ด๋ โ
client_type: public์ผ๋ก RP ๋ฑ๋ก (PKCE-only, secret ์์).์๋ฒ ์ฌ์ด๋ (Next.js / Rails / Express) โ
client_type: confidential๋ก RP ๋ฑ๋ก โclient_id+client_secret๋ฐ๊ธ.
Step 2 ยท ํตํฉ ํจํด โ
SPA / ํด๋ผ์ด์ธํธ ์ฌ์ด๋ (๊ถ์ฅ) โ
์์ SPA (๋ฐฑ์๋ ์ฝ๋ฐฑ ์์ด ๋ธ๋ผ์ฐ์ ์์ ์ง์ ํ ํฐ ๊ตํ) ๋ผ๋ฉด ๊ณต์ SDK @logi-auth/browser@0.1.0 ์ฌ์ฉ:
bash
npm install @logi-auth/browserts
import { LogiAuth } from '@logi-auth/browser';
const auth = new LogiAuth({
clientId: 'logi_xxx',
redirectUri: window.location.origin + '/auth/callback',
});
// Page A โ ๋ก๊ทธ์ธ ์์
await auth.signIn();
// Page B โ ์ฝ๋ฐฑ ํ์ด์ง
const tokens = await auth.handleCallback();์์ธํ API + ์๋ฌ ๋ถ๋ฅ โ SPA Quickstart
์๋ฒ ์ฌ์ด๋ (Next.js / Rails / Express) โ
์๋ฒ์์ client_secret ๋ณด๊ด + ์ฝ๋ฐฑ ์ฒ๋ฆฌ. logi ๋ ํ์ค OIDC discovery (https://api.1pass.dev/.well-known/openid-configuration) ๋ฅผ ์ ๊ณตํ๋ฏ๋ก ์ผ๋ฐ OIDC ๋ผ์ด๋ธ๋ฌ๋ฆฌ โ oauth4webapi, openid-client, next-auth, auth.js โ ๊ฐ issuer: 'https://api.1pass.dev' ๋ง์ผ๋ก ์๋ ์ค์ ๋ฉ๋๋ค.
| ์คํ | ๊ฐ์ด๋ | ํต์ฌ |
|---|---|---|
| Next.js (App Router) | integrations/nextjs | Route Handler + iron-session ํจํด |
| Rails 8 | integrations/rails | Direct OAuth ํด๋ผ์ด์ธํธ (omniauth ๋ฏธ์ฌ์ฉ). โ ๏ธ Hotwire/Turbo ์ฌ์ฉ ์ data-turbo="false" ํ์ |
| Express.js | integrations/express | cookieParser + crypto PKCE |
Step 3 ยท ์น ํนํ ํจ์ ํผํ๊ธฐ โ
โ ๏ธ ๊ธฐ์กด ๋ชจ๋ฐ์ผ RP ์ ์น surface ์ถ๊ฐ ์ redirect_uri ํ์ดํธ๋ฆฌ์คํธ ๊ฐฑ์ ํ์
ํ๋์ client_id ๋ฅผ ๋ชจ๋ฐ์ผ ์ฑ๊ณผ ์น surface ๊ฐ ๊ณต์ ํ๋ฉด (public + PKCE RP ๋ผ๋ฉด ์์ ), ์น ์ฝ๋ฐฑ URL ๋ RP ์ redirect_uris ํ์ดํธ๋ฆฌ์คํธ์ ๋ช
์์ ์ผ๋ก ๋ฑ๋ก๋์ด ์์ด์ผ ํฉ๋๋ค. ๋๋ฝ ์ logi ๋ ์ฆ์ ๊ฑฐ์ :
json
{ "error": "invalid_request", "error_description": "redirect_uri not registered" }์น ๋น๋ ์์ ์ ๋ฐ๋์:
bash
# ํ์ฌ ๋ฑ๋ก๋ ํ์ดํธ๋ฆฌ์คํธ ํ์ธ
logi app show $CLIENT_ID
# ๋๋ฝ์ด๋ฉด ์ถ๊ฐ (๊ธฐ์กด URI ์ ์งํ๊ณ append ํจ)
logi app update $CLIENT_ID --add-redirect-uri "https://app.example.dev/auth/1pass/callback"
# preview/staging ๋๋ฉ์ธ์ด ์๋ค๋ฉด ๊ฐ์ด ๋ฑ๋ก
logi app update $CLIENT_ID --add-redirect-uri "https://preview.example.dev/auth/1pass/callback"
# ๊ฒ์ฆ
logi apps verify $CLIENT_ID -r "https://app.example.dev/auth/1pass/callback"์ด ํจ์ ์ โ์ด๋ฏธ ๋ชจ๋ฐ์ผ๋ก ๋ฑ๋ก๋ RP ์ ์น ํ๋ฆ์ ์๋ก ๋ถ์ผ ๋โ ์์ฃผ ๋ฐ์ํฉ๋๋ค. ์ ๊ท RP ๋ผ๋ฉด ์ฑ ๋ฑ๋ก ๊ฐ์ด๋ ์ redirect_uris ๋ฐฐ์ด์ ๋ชจ๋ surface ์ ์ฝ๋ฐฑ์ ์ฒ์๋ถํฐ ํ ๋ฒ์ ๋ฑ๋กํ์ธ์.
- ์๋ต ํค๋ / Body ์๊ทธ๋ โ
Set-CookieSameSite ์ ์ฑ - Web SSO (๋ฐ์คํฌํฑ Apple/Google) โ ๋ด๋ถ ๋์ ์ฐธ๊ณ ์ฉ. ์ ๊ท RP ํตํฉ์ ์์์ ์ ์๋๋ฉฐ, logi ๊ฐ Apple/Google upstream IdP ํ ํฐ์ ์ด๋ป๊ฒ ์ฒ๋ฆฌํ๋์ง ์๊ณ ์ถ์ ๋๋ง ์ฐธ๊ณ ํ์ธ์
- QR ๋ก๊ทธ์ธ (์ฑ ํธ์ ์น์ธ) โ ๋ฐ์คํฌํฑ ์น์์ ๋ชจ๋ฐ์ผ ์ฑ์ผ๋ก ์น์ธ ์์
- Widget SDK (iframe embed) โ ๋ก๊ทธ์ธ ํ๋ฉด์ iframe ์ผ๋ก ๋ผ์๋ฃ๋ ํจํด
- ์ฒซ ๋ก๊ทธ์ธ ์๋ฃ ํผ โ ์์ฒด ํ์๊ฐ์ ์ถ๊ฐ ํ๋ ํจํด
Step 4 ยท ๋น๋ ์ ์ฒดํฌ โ
- โ
redirect_uris ํ์ดํธ๋ฆฌ์คํธ ๊ฒ์ฆ โ ๋น๋/๋ฐฐํฌ ์ง์
logi apps verify $CLIENT_ID -r "$WEB_CALLBACK_URL"๋ก production / staging / preview ๋๋ฉ์ธ ๊ฐ๊ฐ ํ์ธ. CI ์ ๋ฐ์๋๋ฉด ์์ (--json+ exit code) - RP ํตํฉ ํ ์คํธ
- ๋ณด์ Best Practices (RP ์ธก) โ state/nonce/CSRF
- Troubleshooting
demo.1pass.dev/qrโ ๋ฐ์คํฌํฑ โ ๋ชจ๋ฐ์ผ QR ํธ๋์คํ walking sample (์๋๋ฆฌ์ค deep-link)demo.1pass.dev/oauthโ ๋ฐ์คํฌํฑ OAuth (PKCE) walking sample- Demo ํ์ด์ง ๋๋ฌ๋ณด๊ธฐ โ ์๋๋ฆฌ์ค๋ณ ํ๋ฆ + CSP ์ฒญ์ ํจํด
๊ณตํต ๋ ํผ๋ฐ์ค (ํธ๋ ๋ฌด๊ด) โ
- Authorization Code Flow ยท PKCE ยท Scope ๋ ํผ๋ฐ์ค
- ์ค๋ฅ ์ฝ๋ ยท Token Introspection & JWKS
- Refresh Token ์ ์ฑ
- ๋ก๊ทธ์ธ ๋ฒํผ ์ปดํฌ๋ํธ
- Webhook ์ฐ๋ ยท HMAC ์๋ช ๊ฒ์ฆ
AI ์๊ฒ ํต์งธ๋ก ๋์ง๊ธฐ โ
@/llms-full.txt ๋ฅผ Claude Code ยท Cursor ยท Codex ์ ๋ถ์ด๊ณ ๋ค์ ํ ์ค:
"logi 1pass ๋ฅผ [Next.js / Rails / Express] ์น ์ฑ์ RP ๋ก ํตํฉํด์ค. confidential client + ์๋ฒ ๋ณด๊ด secret ๊ธฐ์ค."
โ env, route, controller, callback handler, ๋ก๊ทธ์ธ ๋ฒํผ UI ๊น์ง ์๋ ์์ฑ๋ฉ๋๋ค.