refactor: 문서 개선 중

This commit is contained in:
donghyeon-ka
2026-09-21 14:30:55 +09:00
parent c93cdea150
commit 805a18f486
1497 changed files with 525837 additions and 59152 deletions
@@ -10,15 +10,15 @@
## Elements and evidence
- **브라우저 SPA** (participant): PKCE transaction과 token set을 처리하고 access token으로 API 요청을 만드는 public client. Evidence: L201L236, L240L280, L303L322.
- **Keycloak** (participant): Authorization code를 발급하고 code와 verifier를 token set으로 교환하는 authorization server. Evidence: L223L263.
- **Resource Server** (participant): Bearer JWT의 signature, issuer, timestamp와 audience를 검증하고 사용자 JSON을 만드는 Spring API. Evidence: L311L353.
- **브라우저 SPA** (participant): PKCE transaction과 token set을 처리하고 access token으로 API 요청을 만드는 public client. Evidence: L233L268, L272L312, L335L354.
- **Keycloak** (participant): Authorization code를 발급하고 code와 verifier를 token set으로 교환하는 authorization server. Evidence: L255L295.
- **Resource Server** (participant): Bearer JWT의 signature, issuer, timestamp와 audience를 검증하고 사용자 JSON을 만드는 Spring API. Evidence: L343L385.
## Relationships
- **브라우저 SPA → Keycloak:** authorization request · S256 challenge. Evidence: L223L236.
- **Keycloak → 브라우저 SPA:** callback · code + state. Evidence: L240L250.
- **브라우저 SPA → Keycloak:** token request · code + verifier. Evidence: L250L261.
- **Keycloak → 브라우저 SPA:** access + refresh + ID token. Evidence: L263L280.
- **브라우저 SPA → Resource Server:** GET /api/me · Bearer access token. Evidence: L303L322.
- **Resource Server → 브라우저 SPA:** subject · username · issuer · audience. Evidence: L342L376.
- **브라우저 SPA → Keycloak:** authorization request · S256 challenge. Evidence: L255L268.
- **Keycloak → 브라우저 SPA:** callback · code + state. Evidence: L272L282.
- **브라우저 SPA → Keycloak:** token request · code + verifier. Evidence: L282L293.
- **Keycloak → 브라우저 SPA:** access + refresh + ID token. Evidence: L295L312.
- **브라우저 SPA → Resource Server:** GET /api/me · Bearer access token. Evidence: L335L354.
- **Resource Server → 브라우저 SPA:** subject · username · issuer · audience. Evidence: L374L408.
@@ -5,13 +5,13 @@
<root>
<mxCell id="0"/>
<mxCell id="1" parent="0"/>
<mxCell id="n_browser" value="브라우저 SPA" tooltip="PKCE transaction과 token set을 처리하고 access token으로 API 요청을 만드는 public client. | Evidence: L201-L236, L240-L280, L303-L322" style="whiteSpace=wrap;html=1;rounded=1;strokeWidth=2;fontSize=14;fontStyle=1;fillColor=#ffffff;strokeColor=#2d4357;verticalAlign=middle;strokeColor=#2563eb;strokeWidth=2;" vertex="1" parent="1">
<mxCell id="n_browser" value="브라우저 SPA" tooltip="PKCE transaction과 token set을 처리하고 access token으로 API 요청을 만드는 public client. | Evidence: L233-L268, L272-L312, L335-L354" style="whiteSpace=wrap;html=1;rounded=1;strokeWidth=2;fontSize=14;fontStyle=1;fillColor=#ffffff;strokeColor=#2d4357;verticalAlign=middle;strokeColor=#2563eb;strokeWidth=2;" vertex="1" parent="1">
<mxGeometry x="45.0" y="35.0" width="150.0" height="64.0" as="geometry"/>
</mxCell>
<mxCell id="n_keycloak" value="Keycloak" tooltip="Authorization code를 발급하고 code와 verifier를 token set으로 교환하는 authorization server. | Evidence: L223-L263" style="whiteSpace=wrap;html=1;rounded=1;strokeWidth=2;fontSize=14;fontStyle=1;fillColor=#ffffff;strokeColor=#2d4357;verticalAlign=middle;" vertex="1" parent="1">
<mxCell id="n_keycloak" value="Keycloak" tooltip="Authorization code를 발급하고 code와 verifier를 token set으로 교환하는 authorization server. | Evidence: L255-L295" style="whiteSpace=wrap;html=1;rounded=1;strokeWidth=2;fontSize=14;fontStyle=1;fillColor=#ffffff;strokeColor=#2d4357;verticalAlign=middle;" vertex="1" parent="1">
<mxGeometry x="255.0" y="35.0" width="150.0" height="64.0" as="geometry"/>
</mxCell>
<mxCell id="n_resource-server" value="Resource Server" tooltip="Bearer JWT의 signature, issuer, timestamp와 audience를 검증하고 사용자 JSON을 만드는 Spring API. | Evidence: L311-L353" style="whiteSpace=wrap;html=1;rounded=1;strokeWidth=2;fontSize=14;fontStyle=1;fillColor=#ffffff;strokeColor=#2d4357;verticalAlign=middle;" vertex="1" parent="1">
<mxCell id="n_resource-server" value="Resource Server" tooltip="Bearer JWT의 signature, issuer, timestamp와 audience를 검증하고 사용자 JSON을 만드는 Spring API. | Evidence: L343-L385" style="whiteSpace=wrap;html=1;rounded=1;strokeWidth=2;fontSize=14;fontStyle=1;fillColor=#ffffff;strokeColor=#2d4357;verticalAlign=middle;" vertex="1" parent="1">
<mxGeometry x="465.0" y="35.0" width="150.0" height="64.0" as="geometry"/>
</mxCell>
<mxCell id="e_authorize" value="authorization request · S256 challenge" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeWidth=2;endArrow=block;endFill=1;" edge="1" parent="1" source="n_browser" target="n_keycloak">
@@ -2,22 +2,22 @@
"harness_version": "0.2.0",
"spec_id": "ap1-browser-bearer-flow",
"spec_version": "1.1",
"spec_sha256": "b78a7bf6ff5d1085c2063a500077d35ab4decf701d59c3d73dc05ca01512e936",
"spec_sha256": "3da0d6ab32a63febbd0d6ef4c19deb5c091b70c3a79f9d6e8e8ac989fb8b9d71",
"source_context": {
"document": "document.md",
"document_sha256": "df4d1a604c74e756672b5b40510abfedb8c67b39af280a5f51985ea9972f5371",
"document_sha256": "15e7c79412ac05ed39d6f3d0c14de8dda92abe7b402139ac2a90492dfe5e162c",
"anchor": {
"kind": "marker",
"value": "ap1-browser-bearer-flow",
"line": 395
"line": 427
}
},
"outputs": [
"ap1-browser-bearer-flow.svg",
"ap1-browser-bearer-flow.drawio",
"ap1-browser-bearer-flow.mmd",
"ap1-browser-bearer-flow.d2",
"ap1-browser-bearer-flow.dot",
"ap1-browser-bearer-flow.drawio",
"ap1-browser-bearer-flow.excalidraw",
"ap1-browser-bearer-flow.alt.md"
],
@@ -2,7 +2,7 @@
<svg xmlns="http://www.w3.org/2000/svg" width="680" height="542" viewBox="0 0 680 542" role="img" aria-labelledby="diagram-title diagram-description">
<title id="diagram-title">AP1 callback code에서 브라우저 Bearer 요청까지</title>
<desc id="diagram-description">브라우저 SPA가 S256 code challenge가 포함된 authorization request를 Keycloak에 보낸다. Keycloak이 code와 state를 callback으로 돌려주면 SPA는 원래 verifier를 포함해 token endpoint에 code를 제출하고 access, refresh, ID token을 받는다. 이어서 SPA가 access token을 Authorization Bearer header에 넣어 Resource Server의 /api/me를 직접 호출하고 사용자 JSON을 받는다.</desc>
<metadata>{&quot;techviz&quot;:{&quot;spec_version&quot;:&quot;1.1&quot;,&quot;id&quot;:&quot;ap1-browser-bearer-flow&quot;,&quot;profile&quot;:&quot;sequence&quot;},&quot;source_context&quot;:{&quot;document&quot;:&quot;document.md&quot;,&quot;document_sha256&quot;:&quot;df4d1a604c74e756672b5b40510abfedb8c67b39af280a5f51985ea9972f5371&quot;,&quot;anchor&quot;:{&quot;kind&quot;:&quot;marker&quot;,&quot;value&quot;:&quot;ap1-browser-bearer-flow&quot;,&quot;line&quot;:395}},&quot;evidence_policy&quot;:&quot;Each factual element cites source lines or is marked assumption.&quot;,&quot;diagram_only&quot;:true}</metadata>
<metadata>{&quot;techviz&quot;:{&quot;spec_version&quot;:&quot;1.1&quot;,&quot;id&quot;:&quot;ap1-browser-bearer-flow&quot;,&quot;profile&quot;:&quot;sequence&quot;},&quot;source_context&quot;:{&quot;document&quot;:&quot;document.md&quot;,&quot;document_sha256&quot;:&quot;15e7c79412ac05ed39d6f3d0c14de8dda92abe7b402139ac2a90492dfe5e162c&quot;,&quot;anchor&quot;:{&quot;kind&quot;:&quot;marker&quot;,&quot;value&quot;:&quot;ap1-browser-bearer-flow&quot;,&quot;line&quot;:427}},&quot;evidence_policy&quot;:&quot;Each factual element cites source lines or is marked assumption.&quot;,&quot;diagram_only&quot;:true}</metadata>
<defs>
<marker id="arrow" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7" markerHeight="7" orient="auto-start-reverse">
<path d="M 0 0 L 10 5 L 0 10 z" />
@@ -50,31 +50,31 @@
</style>
</defs>
<rect class="canvas" width="680" height="542" />
<rect class="node-shape kind-participant emphasis-primary role-participant" data-evidence="201-236,240-280,303-322" x="45.0" y="35.0" width="150.0" height="64.0" rx="7" />
<rect class="node-shape kind-participant emphasis-primary role-participant" data-evidence="233-268,272-312,335-354" x="45.0" y="35.0" width="150.0" height="64.0" rx="7" />
<text class="node-label" x="120.0" y="65.0">브라우저 SPA</text>
<line class="lifeline" x1="120.0" y1="99.0" x2="120.0" y2="512.0" />
<rect class="node-shape kind-participant emphasis-normal role-participant" data-evidence="223-263" x="255.0" y="35.0" width="150.0" height="64.0" rx="7" />
<rect class="node-shape kind-participant emphasis-normal role-participant" data-evidence="255-295" x="255.0" y="35.0" width="150.0" height="64.0" rx="7" />
<text class="node-label" x="330.0" y="65.0">Keycloak</text>
<line class="lifeline" x1="330.0" y1="99.0" x2="330.0" y2="512.0" />
<rect class="node-shape kind-participant emphasis-normal role-participant" data-evidence="311-353" x="465.0" y="35.0" width="150.0" height="64.0" rx="7" />
<rect class="node-shape kind-participant emphasis-normal role-participant" data-evidence="343-385" x="465.0" y="35.0" width="150.0" height="64.0" rx="7" />
<text class="node-label" x="540.0" y="65.0">Resource Server</text>
<line class="lifeline" x1="540.0" y1="99.0" x2="540.0" y2="512.0" />
<polyline class="edge kind-request style-solid emphasis-normal" points="120.0,140.0 330.0,140.0" data-evidence="223-236" />
<polyline class="edge kind-request style-solid emphasis-normal" points="120.0,140.0 330.0,140.0" data-evidence="255-268" />
<rect class="edge-label-bg" x="78.7" y="114.0" width="292.7" height="22" rx="3" />
<text class="edge-label" x="225.0" y="129.0">1. authorization request · S256 challenge</text>
<polyline class="edge kind-response style-dashed emphasis-normal semantic-dashed" points="330.0,202.0 120.0,202.0" data-evidence="240-250" />
<polyline class="edge kind-response style-dashed emphasis-normal semantic-dashed" points="330.0,202.0 120.0,202.0" data-evidence="272-282" />
<rect class="edge-label-bg" x="128.9" y="176.0" width="192.2" height="22" rx="3" />
<text class="edge-label" x="225.0" y="191.0">2. callback · code + state</text>
<polyline class="edge kind-request style-solid emphasis-normal" points="120.0,264.0 330.0,264.0" data-evidence="250-261" />
<polyline class="edge kind-request style-solid emphasis-normal" points="120.0,264.0 330.0,264.0" data-evidence="282-293" />
<rect class="edge-label-bg" x="102.1" y="238.0" width="245.8" height="22" rx="3" />
<text class="edge-label" x="225.0" y="253.0">3. token request · code + verifier</text>
<polyline class="edge kind-response style-dashed emphasis-normal semantic-dashed" points="330.0,326.0 120.0,326.0" data-evidence="263-280" />
<polyline class="edge kind-response style-dashed emphasis-normal semantic-dashed" points="330.0,326.0 120.0,326.0" data-evidence="295-312" />
<rect class="edge-label-bg" x="115.5" y="300.0" width="219.0" height="22" rx="3" />
<text class="edge-label" x="225.0" y="315.0">4. access + refresh + ID token</text>
<polyline class="edge kind-request style-solid emphasis-primary" points="120.0,388.0 540.0,388.0" data-evidence="303-322" />
<polyline class="edge kind-request style-solid emphasis-primary" points="120.0,388.0 540.0,388.0" data-evidence="335-354" />
<rect class="edge-label-bg" x="200.4" y="362.0" width="259.2" height="22" rx="3" />
<text class="edge-label" x="330.0" y="377.0">5. GET /api/me · Bearer access token</text>
<polyline class="edge kind-response style-dashed emphasis-normal semantic-dashed" points="540.0,450.0 120.0,450.0" data-evidence="342-376" />
<polyline class="edge kind-response style-dashed emphasis-normal semantic-dashed" points="540.0,450.0 120.0,450.0" data-evidence="374-408" />
<rect class="edge-label-bg" x="183.7" y="424.0" width="292.7" height="22" rx="3" />
<text class="edge-label" x="330.0" y="439.0">6. subject · username · issuer · audience</text>
</svg>

Before

Width:  |  Height:  |  Size: 7.1 KiB

After

Width:  |  Height:  |  Size: 7.1 KiB