{
`header`: {
`alg`: Algorithm, // the type of signature.
`typ`: Type, // the type of this data structure, JWT.
`uav`: UCAN version.
},
`payload`: {
`iss`: DID, // Required. Issuer DID (sender)
`aud`: DID, // Required. Audience DID (receiver)
`sub`: DID, // Required. Principal that the chain is about (the [Subject])
`cmd`: String, // Required. The [Command] to eventually invoke
`args`: {String : Any}, // Required. Any [Arguments] for the Invocation
`nonce`: Bytes, // Required. Nonce
`meta`: {String : Any}, // Not Required. [Meta] (asserted, signed data)
`nbf`: Integer, // Not Required. "Not before" UTC Unix Timestamp
`exp`: Integer | Null, // Required. Expiration UTC Unix Timestamp
},
`signature`: Bytes // A signature (using alg) of the base64 encoded header and payload concatenated together and delimited by '.'
}
IPFS 데이터에 대한 검증(Verification: IPFS Gateway가 전송한 데이터가 내가 요구한 그 데이터가 맞는가에 대한 검증)을 브라우저가 수행한다면, 브라우저는 IPFS Gateway를 신뢰하지 않더라도 문제 없이 이용할 수 있다 (Trustless Gateway 사용이 가능하다)
이를 위해 Interplanetary Shipyard팀(프로토콜랩으로부터 분사한 개발조직)이 @helia/verified-fetch 라이브러리를 개발/배포한다
Shipyard팀의 다음 목표는 WebRTC와 WebTransport 프로토콜을 이용해서 브라우저에서 직접 Kubo IPFS 노드와 통신하는 것이다
IPFS on the Web in 2024: Update From Interplanetary Shipyard
TURN: 공개 IP가 부여된 서버가 브라우저-to-브라우저 통신을 중계한다 (서버 비용이 든다. 이 글에서는 TURN 서버 대신 GossipSub 프로토콜 이용을 추천한다)
Signaling: libp2p의 WebRTC 통신 초기 연결을 위해서 필요하다
Libp2p relay: 브라우저 노드도 PubSub 프로토콜(GossipSub)을 이용하면 서로 연결될 수 있다 (데모 용도로는 좋으나 배틀 테스트를 거치지 않아서 제품 용도로는 신뢰할 수 없다)
GossipSub 프로토콜을 이용한 브라우저 간 libp2p 통신 수립 가이드 (실제 동작하는 데모, 강추!)
스텝1: 소스레포 복사 및 라이브러리 설치
스텝2: js-libp2p node.js relay 실행
스텝3: 브라우저에서 js-libp2p 실행
스텝4: 브라우저에서 relay로 연결
스텝5: Circuit Relay를 이용, 브라우저를 dialable하게 만들기
스텝6: relay를 브라우저 앱의 부트스트랩 피어로 설정
스텝7: WebRTC를 listen하여 direct connection 만들기
스텝8: PubSub 피어 찾기
결론 1)인푸라 등에서 제공하는 무료 IPFS 노드와 2)Helia 라이브러리와 3)PubSub(GossipSub) 프로토콜을 이용하면 비용 없이 브라우저-to-브라우저 IPFS 네트워크를 구축하는 것이 가능합니다. 다시 말해, 비용 없이 웹3 서비스를 실현할 수 있습니다. 이제 필요한 건 당신의 상상력입니다.
웹3 세상에서는 개인이 identity와 data에 대한 통제권을 갖습니다. 그래서 웹3 세상을 열기 위해서는 identity와 data 관리에 대한 고민이 필수적입니다. 그런 맥락에서 현실 세계의 대표적인 identity 관리 방식인 OAuth2와 OpenID Connect을 살펴봅니다.
OAuth2 표준과 OpenID Connect 표준
OAuth2는 Authorization(이후 authZ)에 대한 표준이다.
반면 OpenID Connect(이후 OIDC)는 Authentication(이후 authN)에 대한 표준이다.
OIDC 표준은 OAuth2 표준을 기반으로 정의되었다.
OIDC AuthZ code flow
그림1. OAuth2 시퀀스
그림2. OIDC 시퀀스
그림1은 OAuth2 authZ code grant type의 동작 시퀀스다.
그림2는 OIDC authZ code flow의 동작 시퀀스다.
두 시퀀스는 사실상 동일하다. 두 시퀀스의 차이점은 id-provider 서버(그림의 'KEYCLOAK')로부터 받아 오는 토큰이다(양쪽 그림의 5번 'Exchange authZ code...' 화살표).
이때 OAuth2 프로토콜은 Access Token을 발급하고, OIDC 프로토콜은 ID Token을 발급한다.
OIDC JWT 표준
ID Token의 규격은 OIDC 표준이 정한다.
ID Token은 JWT(JSON Web Token) 포맷을 따른다.
JWT 토큰에는 토큰 발급자(issuer, 이후 iss)의 priv-key를 이용해서 만든 서명이 포함되어 있어서, 누구나 iss의 pub-key를 이용해서 토큰의 무결성을 검증할 수 있다.
Access Token 관련해서는 정해진 규격이 없다.
OAuth2 표준은 Access Token의 포맷을 규정하지 않는다. 그래서 어떤 포맷을 사용하더라도 표준에 부합한다.
JWT 토큰에 포함된 Signature는 iss의 priv-key를 이용해 만들어진 값이다.
이를 검증하려면 iss의 pub-key가 필요하다.
그런데 JWT 토큰 안에는 iss의 pub-key가 존재하지 않는다. 어디서 가져왔을까?
JWKS URI
JWT 토큰을 검증하려면 iss의 pub-key를 확보해야 한다. 그 절차는 다음과 같다.
토큰에 포함된 iss 속성값으로부터 well-known URL을 유추한다 (iss + '/.well-known/openid-configuration').
(예시로 든 토큰샘플의 iss는 http://localhost:8380 이다. 이 토큰을 검증해서 Signature Verified 결과를 얻으려면 http://localhost:8380/.well-known/openid-configuration 엔드포인트를 호스팅하는 id-provider가 떠 있어야 한다.)
npm init vue@latest명령으로 Vue3와 Pinia를 이용하는 웹앱의 뼈대를 만듭니다.
$ node -v
v16.20.0
$ npm init vue@latest
Vue.js - The Progressive JavaScript Framework
✔ Project name: … todo
✔ Add TypeScript? … No
✔ Add JSX Support? … No
✔ Add Vue Router for Single Page Application development? … No
✔ Add Pinia for state management? … Yes
✔ Add Vitest for Unit Testing? … Yes
✔ Add an End-to-End Testing Solution? › No
✔ Add ESLint for code quality? … No
Scaffolding project in /home/ingee/work/todo/todo...
Done. Now run:
cd todo
npm install
npm run dev
1. Pinia 스토어에 있는 todo 목록을 화면에 표시하자
목표
Pinia 스토어에 todos라는 이름으로 todo 목록을 저장할 계획입니다.
Pinia 스토어에 저장되어 있는 todo 목록을 화면에 표시하는 기능부터 구현하기로 합니다.
Pinia의 초기 상태로 지정한 todo 목록이 화면에 표시되지 않는다고 합니다. 적절합니다.
❯ src/__tests__/App.spec.js (1)
❯ App.vue (1)
× shows todos in store
⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Failed Tests 1 ⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯
FAIL src/__tests__/App.spec.js > App.vue > shows todos in store
AssertionError: expected 'Todo Lorem Ipsum is simply dummy text…' to include 'wake up'
❯ src/__tests__/App.spec.js:35:30
33| const wrapper = createWrapper({ initialState })
34| for (const todo of todos) {
35| expect(wrapper.text()).toContain(todo)
| ^
36| }
37| })
⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯
Test Files 1 failed (1)
Tests 1 failed (1)
Start at 13:08:02
Duration 90ms
FAIL Tests failed. Watching for file changes...
press h to show help, press q to quit
✓ src/__tests__/App.spec.js (1)
Test Files 1 passed (1)
Tests 1 passed (1)
Start at 13:11:57
Duration 108ms
PASS Waiting for file changes...
press h to show help, press q to quit
2. 입력창에 입력한 todo를 Pinia 스토어에 저장하자
목표
화면에 입력한 todo를 Pinia 스토어에 저장할 계획입니다.
todo를 입력하고 Add 버튼을 클릭하면, 해당 항목이 Pinia 스토어에 저장되게 하기로 합니다.
✓ src/__tests__/App.spec.js (2)
Test Files 1 passed (1)
Tests 2 passed (2)
Start at 13:45:47
Duration 160ms
PASS Waiting for file changes...
press h to show help, press q to quit