연결된 웹 스토리지 프로토콜 1.0

W3C 작업 초안

이 문서에 대한 자세한 정보
이 버전:
https://www.w3.org/TR/2026/WD-lws10-core-20260821/
최신 게시 버전:
https://www.w3.org/TR/lws10-core/
최신 편집자 초안:
https://w3c.github.io/lws-protocol/lws10-core/
이력:
https://www.w3.org/standards/history/lws10-core/
커밋 이력
편집자:
Jesse Wright (옥스퍼드 대학교)
Erich Bremer (스토니브룩 대학교)
피드백:
GitHub w3c/lws-protocol (풀 리퀘스트, 새 이슈, 열린 이슈)

초록

Linked Web Storage Protocol 명세는 애플리케이션이 상호 운용 가능한 방식으로 외부에 저장된 데이터에 안전하고 권한이 부여된 접근을 할 수 있도록 하는 것을 목표로 한다.

이 문서의 상태

이 절은 발행 당시 이 문서의 상태를 설명한다. 현재 W3C 발행물과 이 기술 보고서의 최신 개정판 목록은 W3C 표준 및 초안 색인에서 확인할 수 있다.

이는 비공식 제안이다.

이 문서는 Linked Web Storage Working Group에서 권고안 트랙을 사용하여 작업 초안으로 발행했다.

작업 초안으로의 발행은 W3C와 그 회원들의 승인을 의미하지 않는다.

이는 초안 문서이며 언제든지 다른 문서로 갱신, 대체 또는 폐기될 수 있다. 이 문서를 진행 중인 작업이 아닌 다른 것으로 인용하는 것은 적절하지 않다.

이 문서는 W3C 특허 정책에 따라 운영되는 그룹에서 작성했다. W3C는 이 그룹의 산출물과 관련하여 이루어진 특허 공개의 공개 목록을 유지하며, 해당 페이지에는 특허 공개 지침도 포함되어 있다. 개인이 필수 청구항을 포함한다고 믿는 특허를 실제로 알고 있는 경우, 그 개인은 W3C 특허 정책 제6절에 따라 해당 정보를 공개해야 한다.

이 문서는 2025년 8월 18일 W3C 프로세스 문서의 적용을 받는다.

1. 문서 규약

이 절은 비규범적이다.

2. 소개

이 사양은 에이전트의 신원과 권한을 기반으로 클라이언트 애플리케이션이 웹 리소스에 액세스하고 관리할 수 있도록 하는 Linked Web Storage(LWS) 프로토콜을 정의한다.

리소스 서버가 연결된 리소스의 계층 구조를 관리하고 이에 대한 액세스를 제공하는 방식을 표준화함으로써, 이 프로토콜은 사용자가 서로 다른 클라이언트 애플리케이션을 사용하여 동일한 저장 데이터와 상호 작용할 수 있도록 한다. 이러한 연결된 리소스는 항목이 위치한 곳을 설명하는 컨테이너 및 포함 관계와, 리소스가 서로 어떻게 관련되는지를 설명하는 메타데이터를 통해 정의된다.

이 프로토콜은 이러한 리소스를 생성하고, 읽고, 업데이트하고, 삭제하기 위한 표준 작업을 정의한다. 각 리소스는 URI로 식별된다. 클라이언트는 루트 컨테이너에서 리소스 계층 구조를 탐색하면서, 서버 응답에 제공된 링크를 통해 포함된 리소스와 그 관계를 발견한다.

에이전트의 신원은 Linked Web Storage 서버 외부에 있을 수 있는 신원 제공자를 통해 확인된다. 이러한 느슨한 결합은 서버가 반드시 자격 증명을 직접 관리하지 않아도 됨을 의미한다. 대신 서버는 신뢰할 수 있는 신원 제공자가 발급한 토큰으로서 서명된 인증 자격 증명을 수신하고 검증할 수 있다. 따라서 사용자는 해당 서버만을 위한 신규 계정이나 기존 계정이 항상 필요하지 않으며, 기존 신원을 호환 서버에 제시할 수 있다. 예를 들어 LWS는 OpenID Connect, SAML 2.0 및 자체 서명된 제어 식별자(CID) 사양에 정의된 사용자 인증을 사용한다.

권한 부여는 요청하는 에이전트가 리소스에 액세스하거나 해당 리소스에 대한 작업을 수행할 권한이 있는지를 결정한다. 호환 LWS 서버는 각 리소스에 대해 해당 리소스가 비공개인지(즉, 소유자만 이용 가능), 제한된 것인지(즉, 정의된 사용자 집합만 이용 가능), 또는 공개인지(즉, 모든 사용자가 이용 가능)를 결정하는 리소스 관리자를 지정한다. 서버는 각 클라이언트 요청을 처리할 때 리소스 관리자의 액세스 결정을 시행한다.

이 사양은 다음 사용자를 대상으로 한다.

서로 다른 LWS 서버 인스턴스는 각각 자체적인 연결된 리소스 계층 구조를 유지한다. 에이전트는 동일한 식별 정보를 사용하여 여러 서버를 탐색할 수 있으며, 각 서버의 리소스에 대한 액세스는 해당 서버의 리소스 관리자가 부여한 권한에 따라 결정된다. 모든 LWS 서버 인스턴스가 가능한 모든 에이전트 식별자를 지원한다고 보장되지는 않는다. 특정 LWS 서버 인스턴스는 에이전트가 해당 서버 인스턴스가 관리하는 리소스에 액세스하기 위해 특정 신원 제공자를 통해 자신을 식별하도록 요구할 수 있다.

2.1 리소스 접근

LWS 프로토콜은 어떤 주체가 일부 리소스를 일부 에이전트에게 제공할 수 있도록 하는 표준 상호작용을 정의한다.

2.2 보안과 개인정보 보호

리소스 관리자제공되는 리소스를 비공개로 유지할 수 있고, 누구나 공개적으로 사용할 수 있게 할 수도 있으며, 그 가시성을 제한된 집합의 요청 에이전트로 제한할 수도 있다.

2.3 적합성

비규범적이라고 표시된 절뿐 아니라, 이 명세의 모든 작성 지침, 다이어그램, 예시 및 참고는 비규범적이다. 이 명세의 그 밖의 모든 내용은 규범적이다.

이 문서의 핵심어 MAY, MUST, MUST NOT, OPTIONAL, RECOMMENDED, REQUIRED, SHOULD, 및 SHOULD NOT은 여기 표시된 것처럼 모두 대문자로 나타나는 경우에, 그리고 그 경우에만, BCP 14 [RFC2119] [RFC8174]에 설명된 대로 해석된다.

LWS 서버는 이 명세의 관련 "MUST" 문을 모두 준수하는 HTTP 서버 [rfc9112]이다. 구체적으로, 이 문서의 9. 작업에 있는 관련 규범적 "MUST" 문을 준수해야 한다.

LWS 클라이언트는 이 명세의 관련 "MUST" 문을 모두 준수하는 HTTP 클라이언트 [rfc9112]이다. 구체적으로, 이 문서의 9. 작업에 있는 관련 규범적 "MUST" 문을 준수해야 한다.

2.4 범위 다이어그램

다음 다이어그램은 구현을 안내하기 위한 플랫폼 독립적 모델이다.

그림: 시스템 컨텍스트는 LWS 시스템과 그 주요 구성 요소를 보여준다
그림 1 시스템 컨텍스트는 LWS 시스템과 그 주요 구성 요소를 보여준다.

3. 용어

"인가 서버"와 "클라이언트"라는 용어는 OAuth 2.0 인가 프레임워크 [RFC6749]에서 정의한다.

"최종 사용자"와 "발급자"라는 용어는 OpenID Connect Core 1.0 [OPENID-CONNECT-CORE]에서 정의한다.

이 명세는 다음 용어를 정의한다.

(위험 기능) 이슈: 절이 제거될 수 있음

이 명세는 제공된 리소스에 대한 작업, 그 결과로 발생하는 상태 변경, 그리고 요청 에이전트에게 요청한 정보를 제공하거나 작업의 결과를 알리기 위한 응답을 정의한다. 작업제공된 리소스에 대해 수행할 수 있는 다음 작업 중 하나이다:

  • 리소스 생성 -
  • 리소스 읽기 -
  • 리소스 업데이트 -
  • 리소스 삭제 -

다음 절에서는 이러한 작업의 의미론과 응답을 설명하지만, 다음 핵심 응답은 모든 작업에 적용된다:

  • 성공 - 작업이 완료된 것으로 간주된다. 여기에는 제공된 리소스의 내용을 전달하는 리소스 표현이 함께 제공될 수 있다. 성공 응답은 리소스 생성 작업에 대해 정의되지 않는다. 대신 생성됨을 참조한다.
  • 허용되지 않음
  • 알 수 없는 요청자
  • 알 수 없는 오류 - 명세에서 예상하지 못한 오류 조건이 발생한 경우를 위해 예약됨

4. 인증

이 절은 linked web storage 서버와 상호작용하는 에이전트와 최종 사용자를 식별하기 위한 메커니즘을 정의한다. 이 명세는 인증 자격 증명의 특정 형식을 의무화하지는 않지만, 기존 신원 시스템을 linked web storage 권한 부여 프레임워크와 함께 사용할 수 있는 방법을 설명한다.

4.1 인증 자격 증명 데이터 모델

이 절에서 설명하는 데이터 모델은 인증 자격 증명의 모든 구체적인 직렬화에 대한 요구사항을 개괄한다.

인증 자격 증명은 주체에 관한 변조 증거가 있는 클레임을 포함해야 하며, 여기에는 다음이 포함된다:

4.2 인증 자격 증명 검증

인증 자격 증명의 검증에는 자격 증명의 검증자와 발급자 사이의 신뢰 관계가 필요하다. 이 신뢰 관계는 MAY 대역 외 메커니즘을 통해 수립될 수 있다. 검증자와 발급자 사이의 신뢰를 수립하기 위한 추가 메커니즘은 특정 인증 스위트에 개괄된다.

인증 자격 증명MUST 서명되어야 한다. 그 서명에 비대칭 암호화를 사용하는 것이 RECOMMENDED된다.

4.3 인증 자격 증명 유형 식별자

인증 스위트는 토큰 유형 URI와 연관되어야 한다. 인증 스위트는 IANA "OAuth URI" 레지스트리에 정의된 URI를 사용하는 것이 SHOULD된다.

5. 권한 부여

Linked Web Storage는 웹에서 보호된 데이터를 지속적으로 저장하고 관리하기 위한 메커니즘을 설명한다. 권한 부여는 에이전트가 이 보호된 데이터에 접근하기 위해 접근 토큰을 요청하고 제시하는 메커니즘이다.

이 절은 OAuth 2.0 [RFC6749]을 접근 토큰을 획득하고 제시하기 위한 기준 메커니즘으로 삼는 권한 부여 프레임워크를 정의한다. 서버는 이 기준을 넘어서는 추가 권한 부여 메커니즘을 지원할 MAY 있다.

5.1 역할

LWS 권한 부여의 역할은 OAuth 2.0 제1.1절 [RFC6749]에 정의된 역할과 동일하다. 리소스 소유자, 리소스 서버, 클라이언트(모호성을 피하기 위해 이 명세에서는 권한 부여 클라이언트라고 함), 그리고 권한 부여 서버. 스토리지 서버는 LWS 스토리지 명세도 준수하는 리소스 서버의 한 유형이다.

5.2 프로토콜 흐름

이 명세는 클라이언트와 권한 부여 서버 사이의 상호작용뿐 아니라 클라이언트와 준수하는 스토리지 서버 사이의 상호작용을 설명한다.

권한 부여 서버와 스토리지 서버 사이의 상호작용은 이 명세의 범위를 벗어난다. 권한 부여 서버는 스토리지 서버와 동일한 서버일 수도 있고 별도의 엔터티일 수도 있다.

5.2.1 권한 부여 서버 발견

스토리지 서버가 관리하는 모든 보호된 리소스에는 신뢰할 수 있는 권한 부여 서버가 생성한 유효한 접근 토큰이 필요하다. 클라이언트는 보호된 리소스에 승인되지 않은 HTTP 요청을 함으로써 신뢰할 수 있는 권한 부여 서버의 위치를 발견할 수 있다.

401 (Unauthorized) 응답을 생성하는 스토리지 서버는 적어도 하나의 준수하는 챌린지를 포함하는 WWW-Authenticate 헤더 필드를 전송해야 한다. 준수하는 챌린지는 아래에 설명된 매개변수를 포함한다:

  • as_uri REQUIRED — 이 매개변수의 값은 클라이언트가 접근 토큰을 검색할 수 있는 권한 부여 서버를 식별하는 URI이다. 이 매개변수의 값은 유효한 접근 토큰의 iss 클레임과 동일하다.
  • realm REQUIRED — 이 매개변수의 값은 보호 범위를 나타내는 URI이다. 이 값은 접근 토큰의 audience (aud) 클레임에 포함된다. 클라이언트는 MUST 원래 요청의 URI가 이 응답에 제시된 realm 안에 논리적으로 포함되는지 검증해야 한다.

다른 헤더와 매개변수가 포함될 MAY 있다.

401 응답 예시는 아래에 포함되어 있다.

HTTP/2 401 Unauthorized
Link: <https://storage.example/storage_1>; rel="https://www.w3.org/ns/lws#storage"
WWW-Authenticate: Bearer as_uri="https://authorization.example",
                realm="https://storage.example/storage_1",
                error="invalid_token"

5.2.2 권한 부여 서버 메타데이터

권한 부여 서버는 [RFC8414]에 설명된 대로 클라이언트가 엔드포인트 위치와 기능을 발견할 수 있도록 메타데이터 리소스를 제공해야 한다. 이 메타데이터 리소스는 /.well-known/lws-configuration 경로의 URL에서 사용할 수 있어야 한다.

권한 부여 서버는 서버 메타데이터 문서에 subject_token_types_supported 항목을 포함하여 자신이 지원하는 subject token을 알리는 것이 SHOULD된다. 이 항목은 권한 부여 서버의 토큰 엔드포인트에 제공할 수 있는 유효한 subject_token_type 값 목록을 포함하는 JSON 배열이다.

권한 부여 서버 메타데이터 리소스의 예시는 아래에 포함되어 있다.

{
    "issuer": "https://authorization.example",
    "grant_types_supported": [
        "urn:ietf:params:oauth:grant-type:token-exchange"],
    "token_endpoint": "https://authorization.example/token",
    "jwks_uri": "https://authorization.example/jwks",
    "claims_supported": [
        "sub",
        "iss",
        "client_id",
        "aud"],
    "response_types_supported": [
        "token"],
    "subject_token_types_supported": [
        "urn:ietf:params:oauth:token-type:jwt",
        "urn:ietf:params:oauth:token-type:id-token"]
}

5.2.3 토큰 교환

LWS 권한 부여 서버는 준수하는 OAuth 2.0 권한 부여 서버로서, 스토리지 서버와 함께 사용할 접근 토큰을 클라이언트에 발급할 수 있다. 접근 토큰을 발급하려면, 클라이언트는 먼저 인증 자격 증명과 같은 유효한 subject token을 OAuth 2.0 Token Exchange [RFC8693]를 통해 권한 부여 서버에 제시해야 한다.

5.2.3.1 요청

권한 부여 서버의 토큰 엔드포인트는 OAuth 2.0 Token Exchange [RFC8693]에 설명된 대로 urn:ietf:params:oauth:grant-type:token-exchange grant type을 지원해야 한다.

token exchange grant type을 수행할 때 다음 추가 요구사항이 적용된다:

  • resource 매개변수는 REQUIRED이다. 이 매개변수의 값은 URI여야 하며, 결과 접근 토큰의 aud (audience) 클레임을 채우는 데 사용된다. 제공된 값은 WWW-Authenticate 챌린지의 realm 매개변수 응답과 동일하다. 권한 부여 서버는 resource 매개변수가 알 수 없거나 신뢰할 수 없는 스토리지를 식별하는 모든 요청을 거부해야 한다.
  • subject_token 매개변수는 REQUIRED이다. 이 매개변수의 값은 인증 자격 증명과 같은 유효한 subject token을 포함해야 한다.
  • 클라이언트에 접근 토큰을 반환하기 전에, 권한 부여 서버는 제시된 모든 토큰을 성공적으로 검증해야 한다.

토큰 요청의 비규범적 예시(subject_token 매개변수는 잘림).

POST /token HTTP/1.1
Host: authorization.example
Content-Type: application/x-www-form-urlencoded

grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Atoken-exchange
&resource=https%3A%2F%2Fstorage.example%2Fstorage_1
&subject_token=eyJ0eXAiOiJhcytqd3QiLCJhbGciO...fiK51VwhsxJ-siBMR-YFiA
&subject_token_type=urn%3Aietf%3Aparams%3Aoauth%3Atoken-type%3Aid_token
5.2.3.2 응답

토큰 요청이 유효하고 클라이언트가 요청을 할 권한이 있는 경우, 권한 부여 서버 응답은 OAuth 2.0 Authorization Framework [RFC6749]의 제5.1절을 준수해야 한다. 결과 접근 토큰은 JSON Web Token Profile for OAuth 2.0 Access Tokens [RFC9068]를 준수해야 한다.

또한, 접근 토큰은 다음 요구사항을 충족해야 한다:

  • sub (subject) — REQUIRED. 이 클레임은 작업을 수행하는 에이전트를 식별하는 URI여야 한다.
  • iss (issuer) — REQUIRED. 이 클레임은 권한 부여 서버의 URI여야 한다.
  • client_id (client id) — REQUIRED. 이 클레임은 클라이언트를 식별하는 URI여야 한다.
  • aud (audience) — REQUIRED. 이 클레임은 클라이언트가 resource 매개변수에 제공한 URI를 포함해야 한다. 이 값은 접근 토큰이 유효한 엔터티를 제한하는 데 사용된다. 이는 스토리지 서버가 WWW-Authenticate 챌린지의 realm 매개변수에서 제공한 값과 동일하다.
  • exp (expiration) — REQUIRED. 권한 부여 서버는 토큰 도난으로 인한 노출을 제한하기 위해 짧은 수명의 토큰을 발급하는 것이 SHOULD된다 (RECOMMENDED: 300초 이하).
  • iat (issued at) — REQUIRED.
  • jti (JWT ID) — REQUIRED.

성공적인 토큰 응답의 비규범적 예시는 아래에 포함되어 있다.

HTTP/1.1 200 OK
Content-Type: application/json

{
    "access_token":"eyJ0eXAiOiJhcytqd3QiLCJhbGciOiJFUzI1NiIs...DeWt4QuZXso",
    "token_type":"Bearer",
    "expires_in":3600
}

유효하지 않거나 승인되지 않은 모든 요청은 OAuth 2.0 Authorization Framework [RFC6749]의 제5.2절에 설명된 대로 오류 응답을 발생시켜야 한다.

HTTP/1.1 400 Bad Request
Content-Type: application/json

{
    "error":"invalid_request"
}
5.2.3.3 접근 토큰 예시

이 절은 비규범적이다.

권한 부여 서버가 발급한 접근 토큰의 예시는 아래에 포함되어 있다.

{
  "kid": "ec51c6b2",
  "kty": "EC",
  "alg": "ES256",
  "crv": "P-256",
  "typ": "at+jwt"
}
.
{
  "sub": "https://id.example/agent",
  "iss": "https://authorization.example",
  "client_id": "https://app.example/id",
  "aud": "https://storage.example",
  "exp": 1735686300,
  "iat": 1735686000,
  "jti": "550e8400-e29b-41d4-a716-446655440000"
}
.
signature

5.2.4 스토리지 서버에 의한 토큰 검증

클라이언트가 접근 토큰을 보유하게 되면, 이 토큰을 스토리지 서버에 제시한다. 스토리지 서버는 어떤 작업을 수행하기 전에 이 토큰을 검증할 책임이 있다.

5.2.4.1 제시

클라이언트는 [RFC6750]에 정의된 인증 스킴과 함께 Authorization 헤더를 사용하여 스토리지 서버에 접근 토큰을 제시해야 한다.

Authorization: Bearer eyJ0eXAiOiJhcytqd3QiLCJhbGciOiJFUzI1NiIs...DeWt4QuZXso
5.2.4.2 검증

스토리지 서버는 다음 검사를 수행하여 접근 토큰을 검증해야 하며, 실패가 하나라도 있으면 요청을 거부해야 한다:

  • JWT 서명 검증: 권한 부여 서버 메타데이터에 지정된 jwks_uri에서 검색한 권한 부여 서버의 공개 키를 사용하여 JWT 서명을 검증한다. 스토리지 서버는 이러한 키를 캐시하는 것이 SHOULD되며, 키 교체를 지원해야 한다.
  • 발급자 검증: iss 클레임이 예상되는 권한 부여 서버 식별자와 일치하는지 검증한다.
  • Audience 검증: aud 클레임이 정확히 하나의 값을 포함하고, 이 값이 대상 리소스를 논리적으로 포함하는 스토리지 서버를 식별하는 URI인지 검증한다.
  • 시스템 간 허용 가능한 시계 오차를 고려한 시간 검증.
    • 현재 시간이 exp (expiration) 클레임보다 이전인지 검증한다.
    • nbf (not before) 클레임이 있는 경우, 현재 시간이 그보다 이전이 아닌지 검증한다.
    • iat (issued at) 클레임이 미래가 아닌지 검증한다.

검증이 실패하면, 스토리지 서버는 적절한 오류 매개변수(예: invalid_token, invalid_request 또는 insufficient_scope)를 포함하는 WWW-Authenticate 헤더와 함께 401 Unauthorized를 반환해야 한다.

토큰이 그 밖의 면에서는 유효하지만 권한 부여 정책이 요청된 작업을 허용하지 않는 경우, 스토리지 서버는 요청을 거부해야 한다.

6. 발견

6.1 스토리지 설명 리소스

스토리지 설명 리소스는 클라이언트가 스토리지와 상호작용할 때 사용할 수 있는 정보를 제공하며, 여기에는 기능 및 서비스 엔드포인트에 대한 설명이 포함된다.

6.1.1 데이터 모델

스토리지 설명 리소스W3C 제어 식별자 문서[CID-1.0]의 특수화이다. 이 리소스는 [CID-1.0]에서 정의한 데이터 모델을 준수하며, LWS 전용 속성으로 확장된다.

  • id - id 속성은 필수이다. 그 값은 스토리지의 정규 URI여야 한다. [CID-1.0]에 따라 이 URI는 제어 식별자 문서의 정규 URL이기도 하다.
  • type - type 속성은 필수이다. 그 값은 Storage와 같은 문자열이거나 Storage와 같은 항목을 포함하는 문자열 집합이어야 한다 (대소문자 구분).
  • capability - capability 속성은 선택 사항이다. 그 값은 기능 집합이어야 하며, 각 기능은 다음 속성을 포함하는 맵으로 설명된다. 추가 속성이 있을 수 있다.
    • id - id 속성은 선택 사항이다. 존재하는 경우 그 값은 URI여야 한다.
    • type - type 속성은 필수이다. 그 값은 문자열 또는 문자열 집합이어야 한다.
  • service - service 속성은 필수이다. 그 값은 서비스 집합이어야 하며, 각 서비스는 다음 속성을 포함하는 맵으로 설명된다. 추가 속성이 있을 수 있다. 이 집합에는 typeStorageRoot와 같은 서비스가 포함되어야 한다.
    • id - id 속성은 선택 사항이다. 존재하는 경우 그 값은 URI여야 한다.
    • type - type 속성은 필수이다. 그 값은 문자열 또는 문자열 집합이어야 한다.
    • serviceEndpoint - serviceEndpoint 속성은 필수이다. 그 값은 URI여야 한다.
예제 8: 최소 스토리지 설명 리소스
{
  "@context": [
    "https://www.w3.org/ns/cid/v1",
    "https://www.w3.org/ns/lws/v1"
  ],
  "id": "https://storage.example/",
  "type": "Storage",
  "service": [{
    "type": "StorageRoot",
    "serviceEndpoint": "https://storage.example/root/"
  }]
}

6.1.2 발견과 바인딩

저장소 리소스를 대상으로 하는 모든 GETHEAD 요청에 대한 응답은 대상이 저장소의 정식 URI이고, 값이 https://www.w3.org/ns/lws#storage와 같은 관계 (rel) 매개변수를 포함하는 Link 헤더를 반드시 포함해야 한다.

저장소 URI에 대한 요청은 콘텐츠 협상에 따라 다른 형식이 요구되지 않는 한, 미디어 유형이 application/lws+cid이고 저장소 설명 리소스 데이터 모델을 준수하는 문서를 반드시 반환해야 한다.

6.1.3 스토리지 기능

저장소 설명에는 저장소에서 지원하는 추가 기능에 대한 설명이 포함될 수 있다.

6.1.4 스토리지 서비스

저장소 설명 리소스serviceEndpoint저장소 루트 컨테이너의 URI인 StorageRoot 서비스를 반드시 포함해야 한다. 저장소에 연결된 추가 서비스도 포함될 수 있다. 이러한 추가 서비스의 API 정의는 이 명세의 범위를 벗어난다.

6.1.5 스토리지 설명 표현

스토리지 설명반드시 미디어 유형 application/lws+cid으로 직렬화할 수 있어야 한다. @context 속성은 URI https://www.w3.org/ns/cid/v1https://www.w3.org/ns/lws/v1로 시작하는 배열이어야 한다. 콘텐츠 협상을 통해 다른 표현을 제공할 수 있다.

예제 9: 스토리지 설명 리소스
{
  "@context": [
    "https://www.w3.org/ns/cid/v1",
    "https://www.w3.org/ns/lws/v1"
  ],
  "id": "https://storage.example/",
  "type": "Storage",
  "capability": [{
    "type": "https://feature.example/PatchSupport",
    "format": {
      "text/turtle": ["application/sparql-update"],
      "application/n-triples": ["application/sparql-update"],
      "application/linkset+json": ["application/merge-patch+json", "application/json-patch+json"]
    }
  }, {
    "type": "https://feature.example/ResumableUploads"
  }, {
    "type": "https://feature.example/ContentNegotiation",
    "source": "application/ld+json",
    "target": ["text/turtle", "application/n-triples"]
  }, {
    "type": "https://feature.example/ContentNegotiation",
    "source": "image/jpeg",
    "target": ["image/png"]
  }],
  "service": [{
    "type": "StorageRoot",
    "serviceEndpoint": "https://storage.example/root/"
  }, {
    "type": "NotificationService",
    "serviceEndpoint": "https://storage.example/notification/api",
    "subscriptionType": ["WebhookSubscription"]
  }, {
    "type": "TypeIndexService",
    "serviceEndpoint": "https://storage.example/types/index"
  }, {
    "type": "TypeSearchService",
    "serviceEndpoint": "https://storage.example/types/search"
  }, {
    "type": "DataSharingService",
    "serviceEndpoint": "https://storage.example/sharing/api"
  }]
}

7. 논리적 리소스 구성

7.1 컨테이너 모델

Linked Web Storage는 리소스를 컨테이너로 구성한다. 컨테이너는 멤버라고 하는 다른 리소스에 대한 참조를 보유하는 특수한 리소스이다. 컨테이너는 디렉터리나 컬렉션과 유사한 구성 단위로 사용되어 클라이언트가 리소스를 그룹화하고 검색하며 탐색할 수 있게 한다. 컨테이너는 멤버 리소스에 대한 참조를 유지하며, 이러한 멤버 리소스에는 비컨테이너 리소스와 추가 컨테이너 리소스가 모두 포함될 수 있으므로 계층 구조를 형성할 수 있다. 일반적으로 컨테이너에는 메타데이터나 멤버 열거 외에 고유한 콘텐츠가 거의 없으며, 주된 역할은 하위 리소스를 집계하고 구조화하는 것이다. 저장소 시스템의 루트는 상위 부모가 없는 최상위 구성 단위로 사용되는 컨테이너로 지정된다. 컨테이너 표현의 구조는 8.1 컨테이너 표현에서 정의하며, 해당 미디어 유형과 페이지 매김 요구 사항은 12. LWS 미디어 유형에서 정의한다. 저장소는 직접 쓰기를 가능하게 하는 루트 컨테이너로 기능할 수 있다.

모든 LWS 저장소에는 최상위 구성 단위로 사용되는 저장소 루트가 있다. 저장소 루트에는 부모가 없으며 저장소 계층 구조의 진입점 역할을 한다.

LWS의 리소스는 다음 중 하나로 분류된다:

7.2 포함 관계

리소스와 그 부모 컨테이너 사이의 포함 관계rel="up" 링크 관계를 통해 표현된다. 서버는 루트가 아닌 모든 리소스에 대한 GET 및 HEAD 요청의 응답에서 부모 컨테이너를 가리키는 rel="up"이 있는 Link 헤더를 포함해야 한다.

Link: </alice/notes/>; rel="up"

컨테이너의 구성원은 그 표현에서 items 속성을 사용하여 나열된다. 서버가 이 목록을 관리하며, 클라이언트는 이를 직접 수정할 수 없다. 구성원 변경은 리소스 생성 및 삭제의 부수 효과로 발생한다.

7.3 포함 관계 무결성

서버는 항상 포함 관계 무결성을 유지해야 한다:

7.4 리소스 식별

리소스는 URI로 식별된다. 리소스의 URI는 포함 관계 계층 구조에서의 위치와 독립적이다. 서버는 리소스를 생성할 때 URI를 할당하고 클라이언트 힌트를 반영할 수 있지만, 클라이언트는 URI 구조가 포함 관계를 반영한다고 추정하지 않는 것이 좋다.

포함 관계는 URI 경로 구조가 아니라 메타데이터(rel="up" 링크 및 컨테이너 표현의 items 속성)를 통해 표현된다. 이러한 분리는 서버가 명확히 정의된 조직 모델을 유지하면서도 URI 할당에서 유연성을 가질 수 있게 한다.

7.5 컨테이너 구성원 관계와 권한 부여

클라이언트가 컨테이너에 대한 읽기 접근 권한을 가진 경우, 컨테이너 표현은 해당 클라이언트가 접근할 수 있는, 그 컨테이너 안에 포함된 모든 리소스의 식별자를 포함해야 한다. 또한 클라이언트가 접근할 수 없는, 그 컨테이너 안에 포함된 리소스의 식별자도 포함할 MAY 있다.

클라이언트가 컨테이너 목록을 읽을 수 있다는 것은 포함된 리소스 자체에 접근할 수 있음을 의미하지 않으며, 그 반대도 마찬가지이다.

8. 컨테이너

8.1 컨테이너 표현

클라이언트가 컨테이너를 검색하면, 서버는 컨테이너와 그 콘텐츠를 설명하는 구조화된 컨테이너 표현을 반환한다. 이 절에서는 컨테이너 표현의 필수 및 선택적 속성을 정의한다.

8.1.1 컨테이너 속성

컨테이너 표현은 다음 속성을 포함해야 한다:

  • id: 컨테이너의 URI.
  • type: 값 "Container".
  • totalItems: 클라이언트에게 공개될 수 있는, 컨테이너에 포함된 리소스의 총 개수를 나타내는 정수. 이 개수는 정확한 것이 SHOULD되지만 근사치일 MAY 있다.
  • items: 포함된 리소스 설명의 배열(아래 참조). 컨테이너가 비어 있는 경우, 이는 빈 배열이어야 한다. 컨테이너 목록이 페이지네이션되는 경우, items는 현재 페이지의 리소스만 포함한다. 자세한 내용은 페이지네이션을 참조하라.

8.1.2 포함된 리소스 설명

items 배열의 각 항목은 컨테이너 안에 포함된 리소스를 설명한다. 포함된 리소스 설명은 다음을 포함해야 한다:

  • id: 포함된 리소스의 URI.
  • type: 리소스의 유형. "DataResource" 또는 "Container"이거나, 이 두 문자열 중 적어도 하나를 포함하는 배열이어야 한다. 서버는 추가 사용자 정의 유형을 URI로 포함할 MAY 있다 (예: ["DataResource", "http://example.org/customType"]).

포함된 리소스 설명은 다음을 포함하는 것이 SHOULD된다:

  • format: 리소스의 미디어 유형(예: "text/plain", "image/jpeg"). DataResources의 경우 존재해야 한다.
  • size: 정수로 표현된 리소스의 바이트 단위 크기.
  • modified: ISO 8601 date-time 문자열로 표현된, 리소스가 마지막으로 수정된 날짜와 시간.

8.1.3 컨테이너 표현 예시

다음 예시는 두 개의 리소스를 포함하는 /alice/notes/컨테이너를 보여준다:

{
  "@context": "https://www.w3.org/ns/lws/v1",
  "id": "/alice/notes/",
  "type": "Container",
  "totalItems": 2,
  "items": [
    {
      "type": "DataResource",
      "id": "/alice/notes/shoppinglist.txt",
      "format": "text/plain",
      "size": 47,
      "modified": "2025-11-24T12:00:00Z"
    },
    {
      "type": ["DataResource", "http://example.org/customType"],
      "id": "/alice/notes/todo.json",
      "format": "application/json",
      "size": 2048,
      "modified": "2025-11-24T13:00:00Z"
    }
  ]
}

9. 작업

이 절은 Linked Web Storage (LWS) 서버가 지원해야 하는 네 가지 핵심 작업을 정의한다. 이러한 작업은 리소스와 컨테이너를 전송 방식에 독립적인 방식으로 조작하며, 구현 세부사항보다 의미론에 초점을 둔다. 각 작업은 입력, 예상 동작 및 가능한 응답을 지정한다. 응답에는 성공 표시자, 리소스 표현(해당되는 경우) 및 오류 조건이 포함된다. 구현은 이러한 작업을 원자적이고 일관되게 처리해야 하며, 이는 각 작업이 완전히 성공하거나 부분적인 부수 효과 없이 실패해야 함을 의미한다. 오류가 발생한 경우, 응답은 민감한 정보를 누출하지 않으면서 에이전트가 문제를 이해할 수 있을 만큼 충분한 세부 정보를 제공하는 것이 SHOULD된다.

각 핵심 작업(create, read, update, delete)에 대해 사용할 HTTP 메서드, 필요한 헤더 또는 특별한 고려사항(ETags를 통한 동시성 제어, 콘텐츠 협상 및 컨테이너 목록에 대한 페이지네이션 포함), 그리고 서버가 수행하고 반환해야 하는 것을 설명한다. 표준 HTTP 상태 코드는 결과를 나타내는 데 사용되며, 할당량 초과(507 Insufficient Storage) 또는 사전 조건 실패(412 Precondition Failed)와 같은 시나리오에 대한 추가 매핑을 포함한다. 이 바인딩은 HTTP/1.1 및 관련 RFC(예: HTTP 의미론을 위한 [RFC7231], 범위 요청을 위한 [RFC7233], PATCH를 위한 [RFC5789], Web Linking을 위한 [RFC8288], 그리고 Link Sets를 위한 [RFC9264])를 따르려 하므로, 웹 표준과 자연스럽게 통합된다. 발견 가능성은 Link 헤더 및 401 응답의 WWW-Authenticate 헤더와 같은 메커니즘을 통해 강조되어, 하드코딩된 URI 위치를 피한다. 메타데이터 통합은 작업 전반에서 필요하며, 서버 관리 속성과 사용자 관리 속성을 위해 Link Sets의 원자성과 사용을 보장한다.

참고: 이 사양의 모든 예와 마찬가지로, 이 절에 제시된 예(HTTP 요청 및 응답 스니펫)는 일반적인 사용 방식을 설명하기 위한 비규범적 예이다. 실제 요구 사항은 설명문과 표에 명시되어 있다. 또한 이 바인딩은 HTTP를 다루지만(최초 대상 프로토콜로서), LWS 작업은 원칙적으로 향후 다른 프로토콜에 바인딩될 수 있다. 컨테이너 표현의 미디어 유형 요구 사항은 12. LWS 미디어 유형에 정의되어 있다.

9.1 메타데이터

이 절에서는 메타데이터를 LWS 리소스와 연결하는 모델을 정의한다. LWS 메타데이터 시스템은 서버가 유형이 지정된 링크를 사용하여 리소스 간의 관계를 설명할 수 있게 하는 웹 링크 [RFC8288]의 원칙을 기반으로 한다. 메타데이터는 검색 가능성을 향상하고, 자기 설명적 API를 지원하며, 리소스 작업 및 컨테이너 계층 구조와 일치한다.

메타데이터 모델 LWS의 모든 메타데이터는 리소스(링크 컨텍스트)에서 시작되는 유형이 지정된 링크 집합으로 표현된다. 각 링크는 다음으로 구성된다.

메타데이터는 리소스와 해당 표현을 구분하여 해당하는 경우 여러 미디어 유형을 허용한다. 데이터 리소스의 경우 메타데이터에는 각각 format과 선택적 sizeInBytes가 있는 표현이 포함된다. 컨테이너데이터 리소스의 경우 부모 컨테이너 리소스에 대한 링크를 해당 리소스 메타데이터의 일부로 간주한다.

링크 집합 리소스 서버는 저장소의 각 리소스에 대해 [RFC9264]에 따라 메타데이터 링크를 독립형 리소스로 반드시 제공해야 한다.

메타데이터 검색 클라이언트는 주로 GET 또는 HEAD 요청에 대한 응답의 Link 헤더를 통해 메타데이터를 검색한다.

메타데이터 유형

범주 설명
시스템 관리 서버에서 유지 관리하며 읽기 전용이다. linkset, type, format, size, modified를 포함한다.
핵심 메타데이터 클라이언트가 관리한다(서버 제한이 적용됨). up, items, title, creator를 포함한다.
사용자 정의 사용자가 생성한 사용자 지정 어휘와 인덱스.

수정 가능성 고려 사항 핵심 메타데이터는 클라이언트가 수정할 수 있다. 상호 운용성을 보장하기 위해 서버는 기능을 알리는 데 표준 HTTP 헤더를 반드시 사용해야 한다.

  1. 메서드 검색: 서버는 Allow 헤더를 통해 링크 집합 리소스에 대한 GET 및 PATCH 작업 지원을 반드시 알려야 한다.

  2. 패치 형식 검색: 서버는 Accept-Patch 헤더를 통해 JSON 병합 패치 [RFC7386] 지원을 반드시 알려야 한다. Accept-Patch: application/merge-patch+json.

  3. 선택적 메서드: 서버는 PUT 또는 대체 패치 형식을 지원할 수 있다. 지원하는 경우 이러한 메서드와 형식은 각각 Allow 및 Accept-Patch 헤더에 반드시 포함되어야 한다.

[!중요] 클라이언트는 리소스 헤더에 지원이 명시되지 않은 한 PUT 또는 특정 패치 형식의 지원을 가정하지 않는 것이 좋으며, 405 Method Not Allowed 또는 415 Unsupported Media Type 응답을 반드시 적절히 처리해야 한다.

메타데이터 관리 메타데이터는 리소스와 연결된 링크 집합 리소스 URI와 상호 작용하여 관리한다. 서버는 업데이트를 위한 동시성 제어를 반드시 지원해야 한다.

9.2 리소스 생성

리소스 생성 작업은 새 제공되는 리소스를 기존 컨테이너에 추가한다. 이 작업은 데이터 리소스와 하위 컨테이너 생성을 모두 처리한다.

입력:

동작:

가능한 응답:

새 리소스는 대상 컨테이너 URI에 POST를 사용하여 생성하며, 서버가 최종 식별자를 할당한다. 클라이언트는 [RFC8288]의 웹 링크 구문에 따라 POST 요청에 하나 이상의 Link 헤더를 포함하여 새 리소스의 초기 사용자 관리 메타데이터를 제공할 수 있다. 서버 관리 메타데이터는 생성 시 서버에서 반드시 자동으로 생성해야 하며 클라이언트가 제공한 링크로 재정의해서는 안 된다.

성공하면 서버는 새 URI를 Location 헤더에 포함하여 201 상태 코드를 반드시 반환해야 한다. 서버는 부모 컨테이너에 대한 링크 (rel="up") 및 생성된 리소스의 전용 링크 집합 리소스에 대한 링크(rel="linkset"; type="application/linkset+json")를 비롯한 주요 서버 관리 메타데이터의 Link 헤더를 반드시 포함해야 한다. 추가 링크에는 https://www.w3.org/ns/lws#Container 또는 https://www.w3.org/ns/lws#DataResource를 나타내는 rel="type"포함하는 것이 좋다. 본문은 비어 있거나 리소스의 최소 표현을 포함할 수 있다. 일관성을 유지하기 위해 모든 메타데이터 생성과 연결은 리소스 생성과 함께 반드시 원자적으로 수행되어야 한다.

POST(컨테이너 URI에 전송)서버에서 할당한 이름으로 생성: POST를 사용하여 기존 컨테이너 내부에 새 리소스를 추가한다. 서버가 리소스의 식별자를 할당한다. 클라이언트는 생성할 리소스의 유형을 다음과 같이 나타낸다.

예시(POST를 사용하여 새 데이터 리소스 생성):

POST /alice/notes/ HTTP/1.1
Host: example.com
Authorization: Bearer <token>
Content-Type: text/plain
Content-Length: 47

milk
eggs
bread
butter
apples
orange juice

이 예시에서 클라이언트는 컨테이너 /alice/notes/에 POST한다. text/plain 콘텐츠(식료품 목록)를 제공하고 새 리소스의 이름으로 shoppinglist.txt를 제안한다. /alice/notes/가 존재하고 클라이언트가 인가된 경우 서버는 새 데이터 리소스를 생성하여 컨테이너의 멤버 목록에 추가한다.

예시(POST에 대한 응답 — 데이터 리소스):

HTTP/1.1 201 Created
Location: /alice/notes/shoppinglist.txt
Content-Type: text/plain; charset=UTF-8
Link: </alice/notes/shoppinglist.txt.meta>; rel="linkset"; type="application/linkset+json"
Link: </alice/notes/>; rel="up"
Link: <https://www.w3.org/ns/lws#DataResource>; rel="type"
Content-Length: 0

성공하면 새 URI를 Location 헤더에 포함하여 201 Created를 반환한다. 본문은 비어 있거나 최소 표현일 수 있다. 대상 컨테이너 /alice/notes/가 존재하지 않으면 더 적절한 다른 상태 코드가 없는 한 서버는 404 오류 상태를 반드시 반환해야 한다.

컨테이너 생성:컨테이너를 생성하려면 클라이언트는 Container 유형을 나타내는 Link 헤더와 함께 기존 부모 컨테이너에 POST를 사용한다. 예를 들면 다음과 같다.

POST /alice/ HTTP/1.1
Host: example.com
Authorization: Bearer <token>
Content-Length: 0
Link: <https://www.w3.org/ns/lws#Container>; rel="type"

예시(POST에 대한 응답 — 컨테이너):

HTTP/1.1 201 Created
Location: /alice/notes/
Link: </alice/notes/.meta>; rel="linkset"; type="application/linkset+json"
Link: </alice/>; rel="up"
Link: <https://www.w3.org/ns/lws#Container>; rel="type"
Content-Length: 0

이 요청은 /alice/notes/에 새 컨테이너를 생성하며, rel="type"https://www.w3.org/ns/lws#Container인 항목을 포함한 서버 생성 메타데이터도 함께 생성한다.

생성에 관한 추가 참고 사항(HTTP 바인딩):

메타데이터 관리 및 검색(생성과 관련됨): 메타데이터는 주로 읽기 작업을 통해 검색하지만 생성 중에 만들어진다. 클라이언트는 생성 직후 새 리소스 URI에 GET 또는 HEAD를 사용하여 이를 검색할 수 있다. 클라이언트는 특정 메타데이터 링크와 속성을 포함하도록 요청하기 위해 Prefer 헤더를 사용할 수 있다(관계 유형을 통해).

9.3 리소스 읽기

기존 리소스의 표현 또는 컨테이너의 목록을 검색한다.

리소스 읽기 작업은 HTTP GET 요청(및 헤더 전용 요청을 위한 HEAD)으로 리소스 표현을 요청한다. 동작은 대상 URL이 컨테이너인지 또는 컨테이너가 아닌 리소스(데이터 리소스)인지에 따라 다르다. 서버는 메타데이터를 통해 리소스 유형을 구별해야 한다. 모든 응답은 rel="linkset", rel="up", rel="type"과 같은 핵심 관계에 대한 Link 헤더를 포함하여 제8.1절에 정의된 메타데이터와 통합되어야 한다. 서버는 읽기 중 리소스 상태와 그 메타데이터 사이의 원자성을 보장해야 한다.

GET (컨테이너가 아닌 리소스)리소스의 콘텐츠 검색: 전체 콘텐츠를 얻기 위해 리소스 URI에 GET을 보낸다(권한이 있는 경우). 200 OK, 데이터를 포함한 본문, 그리고 저장된 미디어 유형과 일치하는 Content-Type으로 응답한다. 서버는 부분 검색을 위해 [RFC7233]에 따른 범위 요청을 지원해야 한다. 응답은 동시성 제어 및 캐싱을 위해 ETag 헤더를 포함해야 한다.

예시(파일 GET):

GET /alice/notes/shoppinglist.txt HTTP/1.1
Authorization: Bearer <token>
Accept: text/plain

이는 /alice/notes/shoppinglist.txt의 콘텐츠를 요청하며, 클라이언트가 이를 텍스트 형식으로 원한다는 것을 나타낸다. 리소스가 존재하고 텍스트이며 클라이언트가 접근 권한을 가진다고 가정하면:

HTTP/1.1 200 OK
Content-Type: text/plain; charset=UTF-8
Content-Length: 34
ETag: "abc123456"
Link: </alice/notes/shoppinglist.txt.meta>; rel="linkset"; type="application/linkset+json"
Link: </alice/notes/>; rel="up"
Link: <https://www.w3.org/ns/lws#DataResource>; rel="type"

milk
cheese
bread
guacamole
soda
chocolate bars
hash
eggs

서버는 텍스트 콘텐츠를 반환했다(Content-Length가 나타내는 것처럼 총 34바이트). 콘텐츠는 파일에 저장된 정확한 데이터이다. ETag: "abc123456"은 캐싱 또는 동시성 목적의 버전 식별자이다. 응답에는 메타데이터 발견 가능성을 위한 Link 헤더가 포함되며, uptype과 같은 필수 필드를 가진다.

GET (컨테이너 리소스)컨테이너의 콘텐츠 나열: 대상 URI가 (메타데이터 유형을 통해 결정된) 컨테이너에 해당하는 경우, GET 요청은 컨테이너의 구성원 목록을 반환한다. 응답 본문은 LWS 컨테이너 미디어 유형을 사용하는, 컨테이너 표현 절에 정의된 컨테이너 표현이다. 목록에는 각 구성원에 대한 메타데이터가 포함된다: 리소스 식별자(MUST), 유형(MUST), 미디어 유형(DataResources의 경우 MUST), 크기(SHOULD), 및 수정 타임스탬프(SHOULD).

예시(컨테이너 GET):

GET /alice/notes/ HTTP/1.1
Authorization: Bearer <token>
Accept: application/lws+json

컨테이너가 존재하고 클라이언트가 접근 권한을 가진다고 가정하면:

HTTP/1.1 200 OK
Content-Type: application/lws+json
ETag: "container-etag-789"
Link: </alice/notes/.meta>; rel="linkset"; type="application/linkset+json"
Link: </alice/>; rel="up"
Link: <https://www.w3.org/ns/lws#Container>; rel="type"

{
  "@context": "https://www.w3.org/ns/lws/v1",
  "id": "/alice/notes/",
  "type": "Container",
  "totalItems": 2,
  "items": [
    {
      "type": "DataResource",
      "id": "/alice/notes/shoppinglist.txt",
      "format": "text/plain",
      "size": 47,
      "modified": "2025-11-24T12:00:00Z"
    },
    {
      "type": ["DataResource", "http://example.org/customType"],
      "id": "/alice/notes/todo.json",
      "format": "application/json",
      "size": 2048,
      "modified": "2025-11-24T13:00:00Z"
    }
  ]
}

이 예시에서 /alice/notes/컨테이너이다. 응답은 LWS 컨텍스트가 있는 JSON-LD를 사용하며, 필수 메타데이터와 함께 구성원을 나열한다. 각 항목은 type, id, format, size, 및 modified 타임스탬프를 평면 속성으로 포함한다.

모든 경우에, 서버는 응답 헤더에 다음 메타데이터를 포함해야 한다: ETag(구성원 수정 시 변경되는 목록 버전을 나타냄), 그리고 그것이 컨테이너임을 나타내는 rel="type", rel="linkset", 및 rel="up"이 있는 Link 헤더.

HEAD (모든 리소스 또는 컨테이너)헤더/메타데이터만: LWS 서버는 컨테이너와 비컨테이너 모두에 대해 HEAD [RFC9110]를 지원해야 하며, GET과 동일한 헤더(ETag, Content-Type, 메타데이터에 대한 Link 포함)를 반환하되 본문은 반환하지 않는다. 이를 통해 콘텐츠를 전송하지 않고 메타데이터를 검색할 수 있다.

캐싱 및 조건부 요청: LWS는 HTTP 캐싱 의미론을 활용한다. 서버는 If-None-Match(ETags 사용) 또는 If-Modified-Since 헤더를 통한 조건부 요청을 지원해야 한다. 리소스 또는 컨테이너 목록이 변경되지 않은 경우, 중복 전송을 피하기 위해 304 Not Modified로 응답한다. ETags는 동시성 및 캐싱 지원을 위해 모든 GET/HEAD 응답에 제공되어야 한다.

발견 가능성 및 권한 부여: 향상된 발견 가능성을 위해, 서버는 하드코딩된 URI 없이 클라이언트를 안내하는 매개변수와 함께 401 Unauthorized 응답에 WWW-Authenticate 헤더를 포함하는 것이 SHOULD된다. 해당되는 경우 메타데이터 링크를 포함하는 것이 SHOULD된다.

9.4 리소스 갱신

전체 대체 또는 부분 패치를 통해 기존 [served resource]의 상태를 수정한다.

리소스 갱신은 PUT 요청(전체 리소스를 대체) 또는 PATCH 요청(부분 수정을 적용)을 통해 기존 제공되는 리소스의 콘텐츠를 수정한다. 클라이언트는 이러한 작업을 수행하려면 리소스 URL에 대한 쓰기 접근 권한을 가져야 한다. 참고: 이 절은 리소스의 기본 콘텐츠 갱신을 설명한다. 그 메타데이터를 갱신하려면 제9.3.2절을 참조하라. LWS 서버는 리소스 URI에 대한 PUT 및 PATCH 요청을 리소스 콘텐츠에 대한 수정으로만 처리해야 하며, 연결된 linkset 리소스에는 기본적으로 영향을 주지 않아야 한다. 콘텐츠와 메타데이터를 하나의 원자적 작업으로 선택적으로 갱신하려면, 클라이언트는 리소스 URI에 대한 PUT/PATCH 요청에 Link 헤더를 포함하고 'Prefer: set-linkset' 선호사항(RFC 7240에 정의됨)을 지정할 MAY 있다. 이 경우, 서버는 제공된 Link 헤더를 콘텐츠 변경 적용과 더불어 linkset에 대한 대체(PUT의 경우) 또는 부분 갱신(PATCH의 경우)으로 해석해야 한다. 이 동작은 서버에게 OPTIONAL이지만, 지원되는 경우 의도하지 않은 메타데이터 덮어쓰기를 방지하기 위해 Prefer 헤더를 통해 명시적으로 호출되어야 한다. 결합 갱신을 지원하지 않는 서버는 선호사항을 무시하거나 501 Not Implemented로 응답해야 한다.

PUT (전체 리소스 대체) – 리소스 URI에 PUT을 보내며, 본문에는 새 전체 콘텐츠를, Content-Type에는 일치하는 유형(일반적으로 기존 유형과 일관됨)을 포함한다. PUT은 기존 리소스에 대해 멱등적이다. 안전을 위해 현재 ETag와 함께 If-Match를 포함한다(제7.3절 동시성 참조). 불일치하면 412 Precondition Failed 또는 409 Conflict가 발생한다. 검사 없이 갱신은 무조건적이지만 동시 변경을 덮어쓸 위험이 있다. 서버가 리소스에 대해 Etags를 지원하는 경우, If-Match 헤더가 없는 무조건 PUT 요청을 428 Precondition Required 응답으로 거부해야 한다.

예시(리소스를 갱신하기 위한 PUT):

PUT /alice/personalinfo.json HTTP/1.1
Authorization: Bearer <token>
Content-Type: application/json
If-Match: "abc123456"
{
"name": "Alice",
"age": 30,
"city": "New London",
"state": "Connecticut"
}

이 예시에서 클라이언트는 /alice/personalinfo.json의 기존 JSON 리소스를 갱신하고 있다. 이전 GET 또는 HEAD 요청에서 얻은 ETag "abc123456"을 If-Match 헤더에 포함한다. 서버는 이를 현재 ETag와 비교한다. 일치하면, 제공된 JSON으로 콘텐츠를 대체한다. 일치하지 않으면, 서버는 갱신을 거부한다(그 사이 다른 사람이 리소스를 변경했기 때문). 성공 응답: 갱신이 성공하면, 서버는 200 OK로 응답하고 갱신된 표현 또는 일부 확인 정보 (예: 새 콘텐츠 또는 그 일부)를 포함할 수 있다. 또는 서버는 본문 없이 성공을 나타내기 위해 204 No Content로 응답할 수 있다(특히 추가 정보 전달이 필요하지 않은 경우 흔함). 어느 경우든, 서버는 새 버전을 나타내는 새 ETag를 포함하는 것이 SHOULD되며, 본문이 반환되는 경우 Content-Type도 포함할 수 있다. 예:

HTTP/1.1 204 No Content
ETag: "def789012"

이는 클라이언트에게 갱신이 완료되었음을 알리고 새 ETag를 제공한다. 서버가 갱신된 콘텐츠를 반환하기로 선택한 경우, 200 OK를 사용하고 헤더와 함께 본문에 JSON을 포함할 수 있다.

PATCH (부분 갱신) – HTTP PATCH 메서드 [RFC5789]는 클라이언트가 전체 새 콘텐츠를 보내는 대신 리소스에 대한 부분 수정을 지정할 수 있게 한다. 이는 작은 부분만 변경된 큰 리소스에서 전체 콘텐츠를 보내는 것이 비효율적인 경우나, 특정 변경을 적용하고 싶은 동시 편집에서 유용하다. LWS 서버는 [RFC7386]에 정의된 JSON Merge Patch (application/merge-patch+json)를 최소한 지원해야 한다.

리소스 메타데이터 갱신(HTTP PUT / PATCH on Linkset) 리소스의 메타데이터는 rel="linkset"이 있는 Link 헤더를 통해 발견되는 해당 linkset 리소스를 수정하여 갱신된다. 전체 대체(PUT): 전체 linkset 문서를 본문에 담아 linkset 리소스 URI에 PUT 요청을 보내면 리소스의 모든 메타데이터가 대체된다. 부분 갱신(PATCH): linkset 리소스 URI에 대한 PATCH 요청은 특정 링크를 추가, 제거 또는 수정한다.

메타데이터에 대한 동시성 제어 리소스의 메타데이터는 여러 행위자가 수정할 수 있으므로, 동시 덮어쓰기를 방지하는 것이 중요하다. 데이터 무결성을 보장하기 위해, LWS 서버와 클라이언트는 linkset 리소스에 대한 모든 PUT 및 PATCH 작업에서 조건부 요청 [RFC7232]을 사용하는 낙관적 동시성 제어를 구현해야 한다. 서버 책임: 서버는 linkset 리소스에 대한 GET 및 HEAD 요청 응답에 Etag 헤더를 포함해야 한다. linkset에 대한 PUT 또는 PATCH가 성공하면, 서버는 수정된 linkset에 대해 새롭고 고유한 Etag 값을 생성하고 응답의 Etag 헤더에 반환해야 한다. 클라이언트 책임: linkset 리소스를 수정할 때, 클라이언트는 해당 리소스에 대해 가장 최근에 받은 Etag를 포함하는 If-Match 헤더를 포함해야 한다. 처리 규칙: If-Match 헤더 값이 linkset의 현재 Etag와 일치하지 않으면, 서버는 412 Precondition Failed 상태 코드로 요청을 거부해야 한다. linkset URI에 대한 PUT 또는 PATCH 요청에서 If-Match 헤더가 누락된 경우, 서버는 428 Precondition Required 상태 코드 [RFC6585]로 요청을 거부해야 한다. 예시(linkset을 대체하기 위한 PUT): 클라이언트가 먼저 linkset을 가져오고 그 ETag를 받는다.

GET /alice/personalinfo.json.meta HTTP/1.1
Authorization: Bearer <token>
Accept: application/linkset+json
HTTP/1.1 200 OK
Content-Type: application/linkset+json
ETag: "meta-v1"
{
  "linkset": [
    {
      "anchor": "/alice/personalinfo.json",
      "describedby": [ { "href": "/schemas/personal-info.json" } ]
    }
  ]
}

이제 클라이언트는 라이선스를 추가하려 한다. 새롭고 완전한 linkset 문서를 구성하고 If-Match 헤더와 함께 PUT 요청을 보낸다.

PUT /alice/personalinfo.json.meta HTTP/1.1
Authorization: Bearer <token>
Content-Type: application/linkset+json
If-Match: "meta-v1"
{
  "linkset": [
    {
      "anchor": "/alice/personalinfo.json",
      "describedby": [ { "href": "/schemas/personal-info.json" } ],
      "license": [ { "href": "https://creativecommons.org/licenses/by/4.0/" } ]
    }
  ]
}

성공하면, 서버는 성공과 새 ETag로 응답한다.

HTTP/1.1 204 No Content
ETag: "meta-v2"

갱신 규칙 요약 리소스의 콘텐츠만 변경하려는 경우 → 리소스 자체에 PUT/PATCH한다. 리소스의 링크(메타데이터)만 변경하려는 경우 → 리소스와 연결된 linkset 리소스에 PUT/PATCH한다. 콘텐츠와 링크를 모두 변경하려는 경우 → 적절한 Link 헤더와 'Prefer: set-linkset'을 포함하여 리소스 자체에 PUT/PATCH한다. 둘을 모두 설정하는 것은 기본적으로 꺼져 있다.

9.5 리소스 삭제

리소스와 그 연결된 메타데이터를 영구적으로 제거한다.

리소스 삭제 작업은 위의 추상 작업에서 정의한 대로 HTTP DELETE 메서드를 사용하여 구현된다. 이 절은 입력, 동작 및 응답에 대한 HTTP 바인딩을 지정한다.

DELETE 요청은 제거할 리소스 또는 컨테이너의 URI를 대상으로 한다. 클라이언트는 동시성 검사를 위해 ETag가 있는 If-Match 헤더를 포함할 MAY 있다.

삭제 및 포함 관계: 리소스가 삭제되면, 서버는 이를 부모 컨테이너items 목록에서 원자적으로 제거해야 한다. 부모 컨테이너의 totalItems 개수는 그에 따라 갱신되는 것이 SHOULD되며, 그 ETag는 변경을 반영하도록 갱신되어야 한다.

컨테이너가 아닌 리소스의 경우, 서버는 리소스 콘텐츠, 그 연결된 메타데이터(linkset 리소스), 그리고 부모 컨테이너포함 관계 참조를 제거한다.

컨테이너 리소스의 경우, 서버는 기본적으로 비재귀 삭제를 사용한다. 컨테이너가 비어 있지 않고 재귀가 요청되지 않은 경우, 서버는 409 Conflict로 요청을 거부해야 한다. 서버는 삭제되는 컨테이너 내의 모든 포함 리소스에 대한 재귀 삭제를 지원할 MAY 있다. 클라이언트는 [RFC4918]에 정의된 대로 재귀 삭제를 요청하기 위해 Depth: infinity 헤더를 사용해야 한다.

성공 시, 서버는 204 No Content로 응답해야 한다. 서버는 [RFC9110]에 정의된 조건부 요청을 지원하는 것이 SHOULD된다.

클라이언트에게 권한이 없는 경우, 서버는 403 Forbidden(클라이언트의 식별자는 알려져 있지만 권한이 부족한 경우) 또는 401 Unauthorized(유효한 인증이 제공되지 않은 경우)를 반환해야 한다. 리소스 존재를 드러내는 것이 보안 위험을 야기하는 경우, 서버는 대신 404 Not Found를 반환할 MAY 있다.

예시(컨테이너가 아닌 리소스 DELETE):

DELETE /alice/notes/shoppinglist.txt HTTP/1.1
Authorization: Bearer <token>
If-Match: "abc123456"

ETag가 일치하고 클라이언트가 권한을 가진다고 가정하면, 서버는 리소스와 그 메타데이터를 삭제하고 이를 부모 컨테이너 /alice/notes/에서 원자적으로 제거한다:

HTTP/1.1 204 No Content

예시(재귀 없이 비어 있지 않은 컨테이너 DELETE):

DELETE /alice/notes/ HTTP/1.1
Authorization: Bearer <token>

/alice/notes/에 리소스가 포함되어 있다고 가정하면, 서버는 삭제를 거부한다:

HTTP/1.1 409 Conflict
Content-Type: text/plain

Cannot delete container /alice/notes/ - container is not empty.

예시(지원되는 경우 재귀로 컨테이너 DELETE):

DELETE /alice/notes/ HTTP/1.1
Authorization: Bearer <token>
Depth: infinity

서버가 재귀를 지원하고 클라이언트가 모든 콘텐츠에 대한 권한을 가진다고 가정하면, 서버는 컨테이너와 그 하위 항목을 원자적으로 삭제한다:

HTTP/1.1 204 No Content

9.6 HTTP 상태 매핑 요약

이 표는 일관성을 위해 일반 LWS 응답 (제8절에서)를 HTTP 상태 코드와 페이로드에 매핑하며, 페이지네이션, 동시성 제어, 할당량 제약 및 메타데이터 통합과 같은 특정 시나리오를 포함한다:

LWS 응답 HTTP 상태 코드 HTTP 페이로드
성공 (읽기 또는 갱신, 데이터 반환) 200 OK 응답 본문에 있는 리소스 표현(GET의 경우 또는 PUT/PATCH가 콘텐츠를 반환하는 경우), 관련 헤더 (Content-Type, ETag, rel="linkset", rel="up"과 같은 메타데이터용 Link)와 함께. 컨테이너 목록의 경우, 규범적 컨텍스트와 구성원 메타데이터(IDs, types, sizes, timestamps)를 가진 JSON-LD를 포함한다.
Created (새 리소스) 201 Created 일반적으로 응답 본문 없음(또는 새 리소스의 최소 표현). Location 헤더는 새 리소스의 URI로 설정된다. 동시성을 위한 ETag 같은 헤더와 서버 관리 메타데이터에 대한 Link 헤더가 포함되어야 한다.
Deleted (반환할 콘텐츠 없음) 204 No Content 응답 본문 없음. 리소스가 삭제되었거나 요청이 성공했고 더 말할 내용이 없음을 나타낸다. 서버는 영구 삭제에 410 Gone을 사용할 MAY 있다.
Bad Request (잘못된 입력 또는 제약 조건) 400 Bad Request 무엇이 잘못되었는지 설명하는 오류 세부사항. 서버는 구조화된 오류 응답을 위해 [RFC9457]에 정의된 표준 형식을 사용하는 것이 SHOULD되며, 예를 들어 "type", "title", "status", "detail", "instance"와 같은 필드를 가진 JSON 객체를 사용할 수 있다.

10. 알림

이 절에서는 클라이언트가 Linked Web Storage 서버에서 관리하는 리소스의 변경 사항에 관한 시기적절한 업데이트를 수신하는 메커니즘을 정의한다. 이 명세는 공통 알림 데이터 모델과 구독 메커니즘을 정의하며, 구체적인 전달 채널은 별도의 알림 스위트 명세에서 설명한다.

10.1 알림 검색

스토리지는 알림을 지원할 수 있다. 알림을 지원하는 스토리지는 해당 스토리지 설명 리소스의 service 배열에 typeNotificationService인 서비스 객체를 반드시 게시해야 한다.

서비스 객체는 값이 구독 엔드포인트의 URI인 serviceEndpoint 속성을 반드시 포함해야 한다. 서비스 객체는 값이 문자열 배열이며, 각 문자열이 지원되는 구독 유형을 식별하는 subscriptionType 속성을 반드시 포함해야 한다.

서비스 객체에는 추가 속성이 존재할 수 있다.

예제 10: 알림 서비스가 포함된 스토리지 설명
{
  "@context": ["https://www.w3.org/ns/lws/v1"],
  "id": "https://storage.example/",
  "type": "Storage",
  "service": [{
    "type": "NotificationService",
    "serviceEndpoint": "https://notification.example/subscriptions",
    "subscriptionType": [
      "WebhookSubscription"
    ]
  }]
}
참고

서버가 모든 구독 유형을 지원해야 하는 것은 아니다. subscriptionType 배열은 사용할 수 있는 유형을 정확히 게시한다.

10.2 알림 데이터 모델

알림Notification 유형의 JSON-LD 문서로 표현된다. 엔벌로프는 전달 컨텍스트에 관한 메타데이터를 포함하고, 이벤트를 설명하는 Activity Streams 2.0 [ACTIVITYSTREAMS-CORE] [ACTIVITYSTREAMS-VOCABULARY] 활동을 감싼다.

10.2.1 엔벌로프 속성

알림 엔벌로프에는 다음 속성이 있다.

  • type필수. 값은 반드시 문자열 Notification이어야 한다.
  • storage필수. 알림과 연관된 LWS 스토리지를 식별하는 URI.
  • activity필수. JSON 객체 또는 JSON 객체의 배열로, 각 객체는 Activity Streams 2.0 데이터 모델을 준수하며 발생한 이벤트를 설명한다. 10.2.2 활동 속성을 참조하라.
예제 11: 알림 엔벌로프
{
  "@context": [
    "https://www.w3.org/ns/lws/v1",
    "https://www.w3.org/ns/activitystreams"
  ],
  "type": "Notification",
  "storage": "https://storage.example/",
  "activity": {
    "id": "ec4dcc48-6581-4232-81c9-584525a98693",
    "type": ["Delete"],
    "object": {
      "id": "https://storage.example/alice/notes/shopping.txt",
      "type": ["DataResource"]
    },
    "origin": "https://storage.example/alice/notes/",
    "published": "2026-03-26T10:30:00Z"
  }
}

10.2.2 활동 속성

activity 속성 안의 각 활동 객체는 반드시 Activity Streams 2.0 데이터 모델을 준수해야 하며 다음 속성을 반드시 포함해야 한다.

  • id필수. 활동을 고유하게 식별하는 문자열.
  • type필수. 하나 이상의 Activity Streams 2.0 활동 유형을 포함하는 문자열 배열.
  • object필수. 알림의 대상 리소스를 식별하는 JSON 객체. object는 다음 속성을 반드시 포함해야 한다.
    • id필수. 리소스의 URI.
    • type필수. 하나 이상의 리소스 유형을 포함하는 문자열 배열. 이 명세에서 정의하는 값에는 ContainerDataResource가 포함된다. 추가 유형 값을 포함할 수 있다.
  • published필수. 활동이 발생한 시점을 나타내며 [RFC3339]을 준수하는 날짜 및 시간 값.

다음 속성은 선택 사항이다.

  • actor — 작업을 수행한 에이전트를 식별하는 URI.
  • target — 리소스가 추가된 컨테이너를 식별하는 URI. Create 활동과 함께 사용한다.
  • origin — 리소스가 제거된 컨테이너를 식별하는 URI. Delete 활동과 함께 사용한다.

10.2.3 활동 유형

서버는 LWS 리소스의 변경을 나타내기 위해 다음 Activity Streams 2.0 활동 유형을 반드시 지원해야 한다.

  • Create — 컨테이너에 새 리소스가 생성되었다. target 필드는 리소스가 추가된 컨테이너를 나타낸다.
  • Update — 기존 리소스의 콘텐츠 또는 메타데이터가 수정되었다.
  • Delete — 리소스가 제거되었다. origin 필드는 리소스가 제거된 컨테이너를 나타낸다.

다른 활동 유형도 지원할 수 있다.

10.2.4 알림 일괄 처리

서버는 activity 속성의 값으로 활동 객체의 배열을 제공하여 여러 활동을 하나의 알림 엔벌로프로 결합할 수 있다.

예제 12: 일괄 처리된 알림
{
  "@context": [
    "https://www.w3.org/ns/lws/v1",
    "https://www.w3.org/ns/activitystreams"
  ],
  "type": "Notification",
  "storage": "https://storage.example/",
  "activity": [
    {
      "id": "a1b2c3d4-5678-9abc-def0-1234567890ab",
      "type": ["Create"],
      "object": {
        "id": "https://storage.example/alice/notes/meeting.txt",
        "type": ["DataResource"]
      },
      "target": "https://storage.example/alice/notes/",
      "published": "2026-03-26T10:30:00Z"
    },
    {
      "id": "b2c3d4e5-6789-abcd-ef01-234567890abc",
      "type": ["Update"],
      "object": {
        "id": "https://storage.example/alice/profile",
        "type": ["DataResource"]
      },
      "published": "2026-03-26T10:30:01Z"
    }
  ]
}

10.3 구독

알림을 수신하기 위해 구독자NotificationServiceserviceEndpoint에 인증된 POST 요청을 보내 구독을 생성한다. 요청 본문은 반드시 application/lws+json 미디어 유형을 준수해야 한다.

10.3.1 구독 요청

구독 요청은 다음 필드를 반드시 포함해야 한다.

  • type필수. 구독 유형을 식별하는 문자열. 값은 반드시 NotificationServicesubscriptionType 배열에 나열된 유형 중 하나여야 한다.
  • topic필수. 구독에 포함된 리소스를 식별하는 URI 배열.

구독 요청은 구체적인 구독 유형에서 요구하는 추가 필드를 포함할 수 있다.

예제 13: 구독 요청
POST /subscriptions HTTP/2
Host: notification.example
Authorization: Bearer <access-token>
Content-Type: application/lws+json

{
  "@context": ["https://www.w3.org/ns/lws/v1"],
  "type": "WebhookSubscription",
  "topic": [
    "https://storage.example/alice/notes/",
    "https://storage.example/alice/profile"
  ],
  "inbox": "https://receiver.example/hooks/lws"
}

10.3.2 구독 범위

컨테이너에 대한 구독은 재귀적이다. 구독자는 컨테이너 자체와 해당 컨테이너에 전이적으로 포함된 모든 리소스에 관한 알림을 수신한다. 데이터 리소스에 대한 구독은 해당 개별 리소스에만 적용된다.

10.3.3 구독 권한 부여

서버는 구독을 생성할 때 리소스 권한 부여를 반드시 적용해야 한다. 구독자topic 배열에 나열된 모든 리소스에 대해 읽기 접근 권한에 상응하는 권한을 가지고 있지 않으면, 서버는 구독 요청을 반드시 거부해야 한다.

권한 부여는 알림 전달 시점에도 반드시 적용해야 한다. 서버는 이벤트 발생 시점에 구독자에게 읽기 권한이 없는 리소스에 관한 알림을 전달해서는 안 된다. 이는 하위 컨테이너의 리소스를 포함하여 구독 범위 안의 모든 리소스에 적용된다.

구독이 생성된 후 구독자가 구독 범위 안의 리소스 또는 컨테이너에 접근할 수 있는 권한이 철회되면, 서버는 영향을 받는 리소스에 대한 알림 전달을 반드시 중단해야 한다. 구독자topic 배열의 모든 리소스에 대한 접근 권한을 상실하지 않은 한, 서버는 전체 구독을 종료하지 않는 것이 좋다.

참고

구독 시점의 권한 부여는 구독자가 알림을 수신할 정당한 근거가 있는지 검증한다. 전달 시점의 권한 부여는 구독이 생성된 후 발생할 수 있는 권한 부여 변경 사항을 고려하여, 알림이 구독자의 현재 권한과 계속 일치하도록 보장한다.

10.3.4 구독 응답

성공적인 구독 생성 요청에 대한 응답은 반드시 application/lws+json 미디어 유형을 준수해야 하며 다음 필드를 반드시 포함해야 한다.

  • type필수. 요청의 구독 유형과 동일한 문자열.
  • subscription필수. 구독을 나타내는 URL.

10.3.5 구독 유형 식별자

알림 스위트는 반드시 구독 유형 문자열과 연결되어야 한다. 구독 유형 문자열은 NotificationServicesubscriptionType 배열과 구독 요청의 type 필드에서 사용된다.

11. 접근 요청 및 권한 부여

액세스 요청과 액세스 권한 부여는 에이전트가 리소스에 대한 액세스를 요청하고 저장소 제어자가 정의된 제약 조건에 따라 액세스 권한을 부여할 수 있는 메커니즘을 제공한다. 액세스를 요청하고 부여하는 엔드포인트는 특수한 유형의 받은 편지함 역할을 한다.

에이전트액세스 권한 부여를 인가 토큰으로 서버에 제시하지 않는다. 그 대신 액세스 권한 부여는 무엇이 누구에게 어떤 제약 조건으로 인가되었는지에 대한 기록 역할을 한다. 액세스 권한 부여가 생성되거나 취소(삭제)되면 변경 사항을 반영하도록 기반 액세스 정책을 조정하는 것은 서버의 책임이다. 액세스 권한 부여 엔드포인트와 특정 정책 시행 계층 간의 상호 작용은 이 명세의 범위를 벗어난다.

이 절에서 정의하는 액세스 프로필은 작업, 제약 조건 및 할당 대상자를 포함하는 개방형 디지털 권리 언어(ODRL)의 개념을 기반으로 한다. 다른 프로필은 다른 개념적 프레임워크를 사용할 수 있다.

11.1 검색

스토리지는 해당 스토리지 설명 리소스에서 접근 요청접근 권한 부여 지원을 게시할 수 있다. 이러한 지원을 게시하는 경우, 접근 요청 엔드포인트를 설명하는 서비스 객체는 문자열 AccessRequestService와 동일한 type을 반드시 가져야 하며, 접근 권한 부여 엔드포인트를 설명하는 서비스 객체는 문자열 AccessGrantService와 동일한 type을 반드시 가져야 한다. 서비스 객체는 값이 해당 엔드포인트에서 지원되는 접근 프로필을 식별하는 하나 이상의 URI 컬렉션인 conformsTo 속성을 포함하는 것이 좋다. 추가 속성을 포함할 수 있다.

예제 14: 접근 요청 및 권한 부여 서비스가 포함된 스토리지 설명
{
  "@context": [
    "https://www.w3.org/ns/cid/v1",
    "https://www.w3.org/ns/lws/v1"
  ],
  "id": "https://storage.example/",
  "type": "Storage",
  "service": [
    {
      "type": "StorageRoot",
      "serviceEndpoint": "https://storage.example/root/"
    },
    {
      "type": "AccessRequestService",
      "serviceEndpoint": "https://access.example/request/",
      "conformsTo": ["https://www.w3.org/ns/lws#AccessProfile"]
    },
    {
      "type": "AccessGrantService",
      "serviceEndpoint": "https://access.example/grant/",
      "conformsTo": ["https://www.w3.org/ns/lws#AccessProfile"]
    }
  ]
}

11.2 데이터 모델

접근 요청 또는 접근 권한 부여는 식별 및 라우팅을 위한 속성과 요청되거나 허용된 작업을 설명하는 access 객체를 표현하는 데이터 객체이다. ODRL 개념을 사용하여 접근 요청을 설명하는 프로필은 11.3 접근 프로필에서 설명한다.

다음 예제는 접근 요청을 보여 준다. 이 예제는 11.4.1 JSON-LD 직렬화에서 정의한 JSON-LD 직렬화를 사용하여 표시한다.

예제 15: 접근 요청
{
  "@context": [
    "https://www.w3.org/ns/lws/v1"
  ],
  "type": ["AccessRequest"],
  "inbox": "https://id.example/agent/inbox/",
  "storage": "https://storage.example/",
  "access": [{
    "type": ["AccessPolicy"],
    "action": ["read", "create"],
    "assignee": "https://id.example/agent",
    "target": {
      "type": "StorageResource",
      "value": ["https://storage.example/root/projects/"]
    },
    "constraint": [
      {
        "leftOperand": "purpose",
        "operator": "eq",
        "rightOperand": "https://purpose.example/collaboration"
      },
      {
        "leftOperand": "dateTime",
        "operator": "lteq",
        "rightOperand": "2026-06-09T10:00:00Z"
      }
    ]
  }]
}

다음 예제는 접근 권한 부여를 보여 준다. 이 예제는 11.4.1 JSON-LD 직렬화에서 정의한 JSON-LD 직렬화를 사용하여 표시한다.

예제 16: 접근 권한 부여
{
  "@context": [
    "https://www.w3.org/ns/lws/v1"
  ],
  "type": ["AccessGrant"],
  "storage": "https://storage.example/",
  "access": [{
    "type": ["AccessPolicy"],
    "action": ["read"],
    "assignee": "https://id.example/agent",
    "target": {
      "type": "StorageResource",
      "value": ["https://storage.example/root/projects/"]
    },
    "constraint": [
      {
        "leftOperand": "purpose",
        "operator": "eq",
        "rightOperand": "https://purpose.example/collaboration"
      },
      {
        "leftOperand": "dateTime",
        "operator": "lteq",
        "rightOperand": "2026-06-09T10:00:00Z"
      }
    ]
  }]
}

접근 요청접근 권한 부여에는 다른 속성이 존재할 수 있다.

11.2.1 유형

type 속성은 문서의 유형을 나타낸다.

type 속성의 값은 하나 이상의 용어절대 URL 문자열이어야 한다. 접근 요청의 경우 값은 반드시 AccessRequest 용어를 포함해야 한다. 접근 권한 부여의 경우 값은 반드시 AccessGrant 용어를 포함해야 한다. 추가 유형 값을 포함할 수 있다.

이 속성은 필수이다.

이 문서는 접근 요청접근 권한 부여에 대해 다음 유형 값을 정의한다.

  • AccessRequest에이전트가 리소스에 대한 접근을 요청하는 것.
  • AccessGrant스토리지 제어자가 리소스에 대한 접근 권한을 부여하는 승인.
예제 17: type 속성
{
  "type": ["AccessGrant"]
}

11.2.2 스토리지

storage 속성은 접근 요청 또는 접근 권한 부여의 범위가 적용되는 LWS 스토리지를 식별한다.

storage 속성의 값은 반드시 URI여야 한다.

이 속성은 필수이다.

예제 18: storage 속성
{
  "storage": "https://storage.example/"
}

11.2.3 수신함

inbox 속성은 접근 요청 또는 접근 권한 부여와 관련된 알림을 수신하기 위한 URI를 지정한다(11.6 알림 참조).

inbox 속성의 값은 반드시 URI여야 한다.

이 속성은 선택 사항이다.

예제 19: inbox 속성
{
  "inbox": "https://id.example/agent/inbox/"
}

11.2.4 접근

access 속성은 서버에서 지원하는 프로필을 기반으로 하나 이상의 접근 프로필의 특성을 설명한다. ODRL 정보 모델을 기반으로 한 프로필은 11.3 접근 프로필에서 설명한다.

access 속성의 값은 하나 이상의 객체 컬렉션이어야 한다.

이 속성은 필수이다.

11.3 접근 프로필

이 명세는 ODRL 정보 모델ODRL 어휘를 기반으로 하며 다음 URL로 식별되는 접근 프로필을 정의한다. https://www.w3.org/ns/lws#AccessProfile.

11.3.1 유형

type 속성은 접근 정책의 유형을 나타낸다.

type 속성의 값은 하나 이상의 용어절대 URL 문자열이어야 하며, AccessPolicy 용어를 반드시 포함해야 한다. 추가 유형 값을 포함할 수 있다.

이 속성은 필수이다.

예제 20: 접근 정책 유형
{
  "access": [{
    "type": ["AccessPolicy"]
  }]
}

11.3.2 작업

action 속성은 에이전트가 수행하고자 하는 (요청의 경우) 또는 수행하도록 승인된(권한 부여의 경우) 작업을 설명한다.

action 속성의 값은 하나 이상의 문자열 컬렉션이어야 한다. 각 값은 반드시 서버가 인식하는 작업에 해당해야 한다. 다음 값은 반드시 지원해야 한다. read, modify, createdelete. read, modifydelete 값은 ODRL 어휘에서 정의한다. create 값은 이 명세에서 정의한다.

이러한 작업 값은 다음과 같이 LWS 작업에 대응한다.

  • read — 리소스 또는 해당 메타데이터를 가져온다(HTTP GET, HEAD).
  • modify — 기존 리소스를 수정한다(HTTP PUT, PATCH).
  • create — 컨테이너 안에 새 리소스를 생성한다(HTTP POST).
  • delete — 기존 리소스를 제거한다(HTTP DELETE).

이 속성은 필수이다.

예제 21: action 속성
{
  "access": [{
    "action": ["read", "create"]
  }]
}

11.3.3 양수인

assignee 속성은 접근을 요청하는 당사자(요청의 경우) 또는 접근 권한을 부여받는 당사자(권한 부여의 경우)를 식별한다.

assignee 속성의 값은 반드시 URI여야 한다. 공개 접근은 FOAF 어휘Agent 클래스를 사용하여 할당할 수 있으며, 이 클래스는 URI http://xmlns.com/foaf/0.1/Agent로 식별된다.

이 속성은 필수이다.

예제 22: assignee 속성
{
  "access": [{
    "assignee": "https://id.example/agent"
  }]
}

11.3.4 대상

target 속성은 접근 요청 또는 접근 권한 부여가 적용되는 리소스를 식별한다.

target 속성은 다음 속성을 포함하는 객체여야 한다.

  • type — 대상 일치자의 유형을 식별하는 용어 또는 절대 URL 문자열.
  • value — 대상 리소스를 식별하는 데 사용하는 하나 이상의 문자열 컬렉션.

이 명세는 대상 객체에 사용할 수 있도록 다음 type 값을 정의한다.

  • https://www.w3.org/ns/lws#DataResourcelws:DataResource 유형의 리소스와 일치한다.
  • https://www.w3.org/ns/lws#Containerlws:Container 유형의 리소스와 일치한다.
  • https://www.w3.org/ns/lws#StorageResource스토리지가 관리하는 모든 리소스와 일치한다.

서버는 추가 유형 값을 지원할 수 있다.

이 속성은 선택 사항이다.

예제 23: 리소스 유형이 포함된 target 속성
{
  "access": [{
    "target": {
      "type": "StorageResource",
      "value": [
        "https://storage.example/root/2025",
        "https://storage.example/root/2026"
      ]
    }
  }]
}

11.3.5 제약 조건

constraint 속성은 요청되거나 부여되는 접근을 제한하거나 한정하는 조건을 정의한다. 이 속성은 ODRL 제약 조건 모델을 사용한다.

constraint 속성의 값이 존재하는 경우 제약 조건 객체의 컬렉션이어야 한다. 각 제약 조건 객체는 다음 속성을 반드시 포함해야 한다.

  • leftOperand — 제한되는 피연산자를 식별하는 문자열.
  • operator — 비교 연산자를 식별하는 문자열.
  • rightOperand — 비교할 값. 유형은 leftOperand에 따라 달라진다.

여러 제약 조건 객체가 존재하는 경우 모두 충족되어야 한다.

이 프로필 지원을 게시하는 서버는 다음 leftOperand 값을 반드시 지원해야 한다.

  • client — HTTP 요청의 클라이언트 식별자를 나타낸다.
  • format — 대상 HTTP 리소스의 미디어 유형을 나타낸다.
  • type — 리소스의 링크 헤더에 표현된 유형 URL을 나타낸다.
  • purpose — 요청되거나 부여되는 접근의 의도된 용도를 나타낸다.
  • dateTime — 현재 날짜와 시간을 나타낸다.

이 속성은 선택 사항이다.

다음 예제는 이러한 제약 조건의 사용 방법을 보여 준다.

11.3.5.1 목적 제약 조건

다음 예제에서는 purposeleftOperand 값을 사용하여 요청되거나 부여되는 접근의 의도된 용도를 설명한다. eq 연산자를 사용하는 경우 rightOperand 값은 목적을 식별하는 URI이다. isAnyOf 연산자를 사용하는 경우 rightOperand 값은 목적 URI의 배열이며, 명시된 목적이 나열된 값 중 하나와 일치하면 제약 조건을 충족한다.

예제 24: 목적 제약 조건
{
  "access": [{
    "constraint": [
      {
        "leftOperand": "purpose",
        "operator": "isAnyOf",
        "rightOperand": [
          "https://purpose.example/collaboration",
          "https://purpose.example/research"
        ]
      }
    ]
  }]
}
11.3.5.2 클라이언트 제약 조건

다음 예제에서는 clientleftOperand 값을 사용하여 특정 클라이언트 애플리케이션으로 접근을 제한한다. eq 연산자를 사용하는 경우 rightOperand 값은 클라이언트를 식별하는 URI이다.

예제 25: 클라이언트 제약 조건
{
  "access": [{
    "constraint": [
      {
        "leftOperand": "client",
        "operator": "eq",
        "rightOperand": "https://app.example/client-id"
      }
    ]
  }]
}
11.3.5.3 형식 제약 조건

다음 예시에서는 leftOperand 값으로 format을 사용하여 특정 미디어 유형의 리소스로 액세스를 제한한다. eq 연산자를 사용하면 rightOperand 값은 IANA 미디어 유형을 식별하는 문자열이다. isAnyOf 연산자를 사용하면 rightOperand 값은 미디어 유형 문자열의 배열이며, 리소스의 미디어 유형이 나열된 값 중 하나와 일치하면 액세스가 허용된다.

예시 26: 형식 제약 조건
{
  "access": [{
    "constraint": [
      {
        "leftOperand": "format",
        "operator": "isAnyOf",
        "rightOperand": ["image/jpeg", "image/png"]
      }
    ]
  }]
}
11.3.5.4 리소스 유형 제약 조건

모든 LWS 리소스는 유형 값을 나타내는 링크 헤더를 포함한다.

다음 예제에서는 typeleftOperand 값을 사용하여 HTTP Link 헤더에 게시된 리소스 유형을 기반으로 접근을 제한한다. eq 연산자를 사용하는 경우 rightOperand 값은 리소스 유형을 식별하는 URI이다. isAnyOf 연산자를 사용하는 경우 rightOperand 값은 유형 URI의 배열이며, 리소스의 유형이 나열된 값 중 하나와 일치하면 접근이 허용된다.

예제 28: 리소스 유형 제약 조건
{
  "access": [{
    "constraint": [
      {
        "leftOperand": "type",
        "operator": "isAnyOf",
        "rightOperand": [
          "https://type.example/Playlist",
          "https://type.example/Song"
        ]
      }
    ]
  }]
}
11.3.5.5 시간 제약 조건

다음 예제에서는 dateTimeleftOperand 값을 사용하여 특정 시간 범위로 접근을 제한한다. gteq 연산자는 범위의 시작을 정의하고 lteq 연산자는 끝을 정의한다. 시간 제약 조건의 rightOperand 값은 XML 스키마 dateTime 문자열이다.

예제 29: 시간 제약 조건
{
  "access": [{
    "constraint": [
      {
        "leftOperand": "dateTime",
        "operator": "gteq",
        "rightOperand": "2026-03-09T12:00:00Z"
      },
      {
        "leftOperand": "dateTime",
        "operator": "lteq",
        "rightOperand": "2026-06-09T10:00:00Z"
      }
    ]
  }]
}
11.3.5.6 제약 조건 결합

여러 제약 조건 객체가 존재하는 경우 접근을 허용하려면 모두 충족되어야 한다. 다음 예제는 특정 날짜 이전의 특정 클라이언트 애플리케이션으로 접근을 제한한다.

예제 30: 결합된 제약 조건
{
  "access": [{
    "action": ["read"],
    "assignee": "https://id.example/agent",
    "target": {
      "type": "StorageResource",
      "value": ["https://storage.example/root/projects/"]
    },
    "constraint": [
      {
        "leftOperand": "dateTime",
        "operator": "lteq",
        "rightOperand": "2026-06-09T10:00:00Z"
      },
      {
        "leftOperand": "client",
        "operator": "eq",
        "rightOperand": "https://app.example/client-id"
      }
    ]
  }]
}

11.4 직렬화

이 절에서 정의한 데이터 모델은 특정 직렬화와 독립적이다.

11.4.1 JSON-LD 직렬화

이 명세는 접근 요청접근 권한 부여를 위한 JSON-LD 직렬화를 정의한다. 이 직렬화를 사용하는 문서는 값이 https://www.w3.org/ns/lws/v1을 포함하는 순서 있는 집합인 @context 속성을 반드시 포함해야 한다. 확장 용어를 정의하기 위한 추가 컨텍스트 항목을 포함할 수 있다.

이 직렬화와 연결된 미디어 유형은 application/lws+json이다.

예제 31: JSON-LD @context
{
  "@context": [
    "https://www.w3.org/ns/lws/v1"
  ]
}

11.5 프로토콜

접근 요청접근 권한 부여 엔드포인트는 LWS 컨테이너이며, 이 명세에서 정의한 규칙을 반드시 준수해야 한다.

이러한 엔드포인트는 최소한 GET 및 POST 작업을 지원해야 한다. DELETE 작업은 권장된다. 다른 작업도 지원할 수 있다.

이러한 엔드포인트는 요청 및 응답 페이로드 모두에 대해 11.4.1 JSON-LD 직렬화에서 정의한 JSON-LD 직렬화를 반드시 지원해야 한다. 서버는 추가 직렬화를 지원할 수 있다.

에이전트접근 요청 엔드포인트에 POST 요청을 제출하여 접근 요청을 생성한다. 스토리지 제어자접근 권한 부여 엔드포인트에 POST 요청을 제출하여 접근 권한 부여를 생성한다.

성공한 POST 작업은 새 리소스의 URL로 설정된 Location 헤더를 사용하여 반드시 응답해야 한다.

11.5.1 접근 요청 엔드포인트

  • POST / — 접근 요청을 생성한다.
  • GET / — 접근 요청 목록을 가져온다.
  • GET /:id — 특정 접근 요청을 가져온다.
  • DELETE /:id — 접근 요청을 취소한다.

11.5.2 접근 권한 부여 엔드포인트

  • POST / — 접근 권한 부여를 생성한다.
  • GET / — 접근 권한 부여 목록을 가져온다.
  • GET /:id — 특정 접근 권한 부여를 가져온다.
  • DELETE /:id — 접근 권한 부여를 철회한다.

11.6 알림

이슈 103: LWS 알림 기능 작업 항목

이 절은 아직 정의되지 않은 LWS 알림 절과 일치하도록 조정해야 한다.

알림은 접근 요청접근 권한 부여의 변경 사항을 에이전트스토리지 제어자에게 알리는 메커니즘을 제공한다. 접근 요청 또는 접근 권한 부여inbox 속성이 존재하는 경우 서버는 해당 엔드포인트로 알림을 전달하여 양수인에게 이벤트를 알리는 것이 좋다.

알림의 직렬화는 LWS 알림 데이터 모델의 요구 사항을 반드시 준수해야 한다.

inbox 엔드포인트로 전달되는 알림은 알림 전달에 대해 LWS 프로토콜에서 정의한 요구 사항을 반드시 준수해야 한다.

참고

이 절에서 설명하는 알림 메커니즘은 inbox 속성을 통해 알림을 검색하고 해당 수신함에 POST 요청을 보내 전달하는 연결된 데이터 알림 패턴과 유사하다.

11.6.1 알림 이벤트

서버는 다음 이벤트에 응답하여 알림을 보내는 것이 좋다.

서버는 다른 이벤트에 응답하여 알림을 보낼 수 있다.

12. LWS 미디어 유형

12.1 LWS 미디어 유형

LWS 스토리지 설명반드시 application/lws+cid 미디어 유형으로 직렬화할 수 있어야 한다. application/lws+cid 미디어 유형은 W3C 제어 식별자 문서 [CID-1.0]를 특수화하고 LWS 어휘로 확장한 문서를 식별한다.

LWS 컨테이너 표현반드시 application/lws+json 미디어 유형을 지원해야 한다.

LWS 컨테이너 표현은 JSON-LD 규칙을 사용하지만, LWS의 제약 조건과 요구 사항은 특정 미디어 유형의 사용을 정당화한다. LWS 컨테이너는 JSON-LD의 제한된 프로파일로 간주할 수 있으므로, 구현은 application/ld+json; profile="https://www.w3.org/ns/lws/v1" 미디어 유형을 application/lws+json과 동등한 것으로 간주하는 것이 좋다.

12.1.1 미디어 유형 동등성

컨테이너 표현에서 application/lws+json, application/ld+jsonapplication/json 미디어 유형은 동등하다. 응답 본문은 8.1 컨테이너 표현에 정의된 컨테이너 표현 구조를 준수하는 동일한 JSON-LD 문서이며, Content-Type 응답 헤더만 달라진다. 서버는 이러한 미디어 유형 중 하나에 대한 요청을 반드시 수용해야 하며, Content-Type 응답 헤더를 요청된 미디어 유형으로 반드시 설정해야 한다.

컨테이너 응답의 Content-Type은 요청의 Accept 헤더에 따라 달라지므로, 이러한 응답에는 Vary: Accept 헤더를 포함하는 것이 좋다 [RFC9110].

참고(비규범적): 이 동등성은 위의 세 가지 미디어 유형에만 적용된다. 다른 모든 HTTP 리소스와 마찬가지로, 서버는 표준 콘텐츠 협상 [RFC9110]을 통해 컨테이너의 추가 표현(예: text/turtle)을 제공할 수 있다. 이 사양은 이러한 지원을 요구하지도 배제하지도 않는다.

12.1.2 페이지네이션

컨테이너와 같은 특정 복합 리소스는 많은 리소스를 보유할 수 있다. 클라이언트가 목록을 점진적으로 가져올 수 있도록, 서버는 멤버 수가 서버에서 정한 임계값을 초과하는 컨테이너에 대해 페이지네이션을 지원하는 것이 좋다.

12.1.2.1 페이지네이션 모델

페이지네이션은 링크를 기반으로 한다. 서버는 HTTP Link 헤더 [RFC8288]를 통해 페이지네이션 URI를 제공하여, 클라이언트가 숫자 오프셋에 의존하지 않고 전체 목록을 탐색할 수 있도록 한다.

목록에 페이지네이션이 적용되면 응답 본문에는 현재 페이지의 항목만 포함된다. 복합 리소스의 id, typetotalItems 속성은 전체 멤버 구성을 나타내지만, items에는 현재 페이지의 리소스만 포함된다.

12.1.2.3 페이지 요청

클라이언트는 첫 페이지를 가져오기 위해 복합 리소스의 URI를 요청한다. 응답에는 클라이언트가 이후 페이지를 가져오기 위해 따라가는 페이지네이션 Link 헤더가 포함된다. 서버는 이전 탐색 중 얻은 페이지네이션 URI를 통해 특정 페이지에 직접 액세스하는 기능도 지원할 수 있다.

페이지네이션된 응답이 반환되면 서버는 반드시 200 OK로 응답해야 한다. 응답 본문의 totalItems 속성은 현재 페이지만이 아니라 모든 페이지에 걸친 전체 항목 수를 나타내는 것이 좋다.

12.1.2.4 예: 페이지네이션된 컨테이너

요청:

GET /alice/photos/ HTTP/1.1
Authorization: Bearer <token>
Accept: application/lws+json

응답(첫 페이지):

HTTP/1.1 200 OK
Content-Type: application/lws+json
ETag: "photos-page1-etag"
Link: </alice/photos/.meta>; rel="linkset"; type="application/linkset+json"
Link: </alice/>; rel="up"
Link: <https://www.w3.org/ns/lws#Container>; rel="type"
Link: </alice/photos/?page=1>; rel="first"
Link: </alice/photos/?page=3>; rel="last"
Link: </alice/photos/?page=2>; rel="next"

{
  "@context": "https://www.w3.org/ns/lws/v1",
  "id": "/alice/photos/",
  "type": "Container",
  "totalItems": 150,
  "items": [
    {
      "type": "DataResource",
      "id": "/alice/photos/vacation.jpg",
      "format": "image/jpeg",
      "size": 248392,
      "modified": "2025-11-20T10:30:00Z"
    },
    {
      "type": "DataResource",
      "id": "/alice/photos/portrait.png",
      "format": "image/png",
      "size": 102400,
      "modified": "2025-11-21T14:15:00Z"
    }
  ]
}

요청(다음 페이지):

GET /alice/photos/?page=2 HTTP/1.1
Authorization: Bearer <token>
Accept: application/lws+json

응답(중간 페이지):

HTTP/1.1 200 OK
Content-Type: application/lws+json
ETag: "photos-page2-etag"
Link: </alice/photos/.meta>; rel="linkset"; type="application/linkset+json"
Link: </alice/>; rel="up"
Link: <https://www.w3.org/ns/lws#Container>; rel="type"
Link: </alice/photos/?page=1>; rel="first"
Link: </alice/photos/?page=1>; rel="prev"
Link: </alice/photos/?page=3>; rel="next"
Link: </alice/photos/?page=3>; rel="last"

{
  "@context": "https://www.w3.org/ns/lws/v1",
  "id": "/alice/photos/",
  "type": "Container",
  "totalItems": 150,
  "items": [
    {
      "type": "DataResource",
      "id": "/alice/photos/sunset.jpg",
      "format": "image/jpeg",
      "size": 315000,
      "modified": "2025-11-22T09:00:00Z"
    }
  ]
}

13. JSON-LD 컨텍스트

LWS JSON-LD 컨텍스트는 URL https://www.w3.org/ns/lws/v1로 식별된다. 해당 URL에서 확인되는 문서의 SHA2-256 다이제스트는 아래 표에 포함되어 있다.

컨텍스트 URL 및 해시
URL: https://www.w3.org/ns/lws/v1
SHA2-256 다이제스트: TODO: 컨텍스트 문서가 확정되면 JSON-LD 컨텍스트 다이제스트를 포함할 것

다이제스트는 다음과 같은 명령으로 확인할 수 있다. curl -sL -H "Accept: application/ld+json" https://www.w3.org/ns/lws/v1 | openssl dgst -sha256

참고
프로덕션 시스템은 런타임에 원격 JSON-LD 컨텍스트 문서를 가져오지 않는 것이 좋다. 컨텍스트를 로컬에 번들로 포함하거나 캐시하면 외부 인프라에 대한 런타임 종속성이 제거되고, 지연 시간이 줄어들며 컨텍스트 조작 공격을 방지할 수 있다.

14. 리소스 식별

URI 체계, 리소스 명명 규칙 및 확인 메커니즘을 포함하여 LWS 프로토콜 내에서 리소스를 식별하고 주소를 지정하는 방법을 정의한다. 이 절은 다른 절로 이동할 수 있다. 예: 리소스 접근

의도적으로 비워 둠

15. 이식성 고려 사항

상호 운용성을 유지하면서 LWS 구현이 다양한 플랫폼, 환경 및 스토리지 백엔드에서 작동하도록 보장하기 위한 고려 사항을 설명하고, 스토리지 제공자를 변경할 수 있는 기능을 제공한다.

의도적으로 비워 둠

16. 보안 고려 사항

이 절은 비규범적이다.

안전한 LWS 배포를 위한 위협 모델, 보안 요구 사항 및 구현 지침을 다루는 정식 보안 고려 사항 절.

OAuth 2.0 보안을 위한 현행 최선의 관행 [RFC9700]에서 설명하는 권고 사항은 이 명세에 적용된다.

16.1 전송 보안

이 절은 비규범적이다.

전송 계층 보안(TLS)은 변조, 스푸핑 및 정보 노출을 방지하는 중요한 메커니즘이다. TLS로 보호된 통신은 [RFC6125]에 따라 검증할 수 있다. 구현 보안 고려 사항은 “전송 계층 보안(TLS) 및 데이터그램 전송 계층 보안(DTLS)의 안전한 사용을 위한 권고 사항” [RFC9325]에서 확인할 수 있다.

16.2 토큰 보안

이 절은 비규범적이다.

전달자 토큰과 디지털 자격 증명은 도난과 재전송에 취약하다. 완화 조치에는 합리적으로 짧은 수명을 사용하고, 토큰을 특정 대상에 바인딩하며, 토큰을 안전하게 저장하는 것이 포함된다.

16.3 접근 요청 및 권한 부여

이 절은 비규범적이다.

16.4 알림

이 절은 비규범적이다.

17. 개인정보 보호 고려 사항

이 절은 비규범적이다.

데이터 최소화, 사용자 동의 및 개인정보 보호 구현 패턴을 포함한 LWS 프로토콜의 개인정보 보호 영향을 설명한다.

자격 증명은 사용자와 에이전트에 관한 정보를 포함한다. 디지털 서명은 변조를 방지할 수 있지만, 클라이언트나 제3자가 암호화되지 않은 자격 증명 내부의 값을 읽을 수 있다.

따라서 자격 증명 발급자에게는 인증 또는 권한 부여에 필요한 정보만 포함하는 토큰을 생성하고, 필요한 경우가 아니면 민감한 속성을 포함하지 않을 것을 권장한다.

일반적으로 암호화되지 않은 자격 증명 데이터를 로그에 기록하는 것은 안티패턴이다. 필요한 경우 구현은 자격 증명을 잘라내거나 해시하여 자격 증명 주체의 개인정보를 보호할 수 있다.

JWT에서 가명 식별자를 사용할 때도 스토리지 서버는 시간이 지나면서 동일한 에이전트의 요청을 서로 연관 지을 수 있다. 이 경우 사용자 개인정보를 보호하기 위해 클라이언트 애플리케이션은 각 JWT를 한 번만 사용하는 JWT의 일괄 발급을 요청할 수 있다. 이것은 스토리지 서버가 JWT 콘텐츠의 유사성이나 요청 발신 IP 주소와 같은 다른 정보를 사용하여 요청을 연관 짓는 것을 방지하지 않는다. 가명 식별자를 사용할 때 권한 부여 서버는 동일한 식별자를 두 번 이상 발급하지 않도록 주의해야 한다.

17.1 접근 요청 및 권한 부여

이 절은 비규범적이다.

17.2 알림

이 절은 비규범적이다.

18. IANA 고려 사항

이 절은 비규범적이다.

18.1 well-known URI 레지스트리

이 명세는 RFC 5785 [RFC5785]에서 설정한 “Well-Known URI” 레지스트리에 다음 값을 추가한다.

18.2 OAuth 권한 부여 서버 메타데이터 레지스트리

이 명세는 [RFC8414]에서 설정한 “OAuth 권한 부여 서버 메타데이터” 레지스트리에 다음 값을 추가한다.

18.3 application/lws+json 미디어 유형

이 명세는 Linked Web Storage 컨테이너 형식을 준수하는 문서를 식별하기 위해 application/lws+json 미디어 유형을 명시적으로 등록한다.

Linked Web Storage 형식은 JSON-LD 규칙을 사용하지만, LWS 구현에는 특정 미디어 유형의 사용을 정당화하는 여러 제약 조건과 추가 요구 사항이 있다는 점에 유의하라.

LWS 컨테이너는 JSON-LD의 제한된 프로필로 간주할 수 있으므로, 구현은 application/ld+json; profile="https://www.w3.org/ns/lws/v1" 미디어 유형을 application/lws+json과 동등한 것으로 간주하는 것이 좋다.

18.4 application/lws+cid 미디어 유형

이 명세는 Linked Web Storage 프로토콜을 준수하는 스토리지 설명 문서를 W3C 제어 식별자 1.0 문서 형식의 특수화로 식별하기 위한 application/lws+cid 미디어 유형을 등록한다.

A. 감사의 말

이 절은 비규범적이다.

이 명세는 Solid Protocol [Solid-Protocol]에서 많은 부분을 가져왔으며, 이 프로토콜은 시간이 지남에 따라 Sarven Capadisli, Tim Berners-Lee, Kjetil Kjernsmo, Ruben Verborgh, Justin Bingham, Dmitri Zagidulin이 편집했다.

B. 참고문헌

B.1 규범적 참고문헌

[ACTIVITYSTREAMS-CORE]
Activity Streams 2.0. James Snell; Evan Prodromou. W3C. 2017년 5월 23일. W3C 권고안. URL: https://www.w3.org/TR/activitystreams-core/
[ACTIVITYSTREAMS-VOCABULARY]
활동 어휘. James Snell; Evan Prodromou. W3C. 2017년 5월 23일. W3C 권고안. URL: https://www.w3.org/TR/activitystreams-vocabulary/
[CID-1.0]
제어 식별자 v1.0. Michael Jones; Manu Sporny. W3C. 2025년 5월 15일. W3C 권고안. URL: https://www.w3.org/TR/cid-1.0/
[FOAF]
FOAF 어휘 명세 0.99(Paddington 에디션). Dan Brickley; Libby Miller. FOAF 프로젝트. 2014년 1월 14일. URL: http://xmlns.com/foaf/spec/
[JSON-LD11]
JSON-LD 1.1. Gregg Kellogg; Pierre-Antoine Champin; Dave Longley. W3C. 2020년 7월 16일. W3C 권고안. URL: https://www.w3.org/TR/json-ld11/
[ODRL-MODEL]
ODRL 정보 모델 2.2. Renato Iannella; Serena Villata. W3C. 2018년 2월 15일. W3C 권고안. URL: https://www.w3.org/TR/odrl-model/
[ODRL-VOCAB]
ODRL 어휘 및 표현 2.2. Renato Iannella; Michael Steidl; Stuart Myles; Víctor Rodríguez-Doncel. W3C. 2018년 2월 15일. W3C 권고안. URL: https://www.w3.org/TR/odrl-vocab/
[OPENID-CONNECT-CORE]
정오표 세트 2를 반영한 OpenID Connect Core 1.0. N. Sakimura; J. Bradley; M. Jones; B. de Medeiros; C. Mortimore. OpenID 재단. 2023년 12월 15일. 최종본. URL: https://openid.net/specs/openid-connect-core-1_0.html
[RFC2119]
요구 수준을 나타내기 위해 RFC에서 사용하는 핵심 단어. S. Bradner. IETF. 1997년 3월. 현행 최선의 관행. URL: https://www.rfc-editor.org/info/rfc2119/
[RFC3339]
인터넷의 날짜 및 시간: 타임스탬프. G. Klyne; C. Newman. IETF. 2002년 7월. 제안 표준. URL: https://www.rfc-editor.org/info/rfc3339/
[RFC3986]
URI(Uniform Resource Identifier): 일반 구문. T. Berners-Lee; R. Fielding; L. Masinter. IETF. 2005년 1월. 인터넷 표준. URL: https://www.rfc-editor.org/info/rfc3986/
[RFC4918]
웹 분산 저작 및 버전 관리를 위한 HTTP 확장(WebDAV). L. Dusseault, 편집. IETF. 2007년 6월. 제안 표준. URL: https://www.rfc-editor.org/info/rfc4918/
[RFC5789]
HTTP의 PATCH 메서드. L. Dusseault; J. Snell. IETF. 2010년 3월. 제안 표준. URL: https://httpwg.org/specs/rfc5789.html
[RFC6585]
추가 HTTP 상태 코드. M. Nottingham; R. Fielding. IETF. 2012년 4월. 제안 표준. URL: https://httpwg.org/specs/rfc6585.html
[RFC6749]
OAuth 2.0 권한 부여 프레임워크. D. Hardt, 편집. IETF. 2012년 10월. 제안 표준. URL: https://www.rfc-editor.org/info/rfc6749/
[RFC6750]
OAuth 2.0 권한 부여 프레임워크: 전달자 토큰 사용. M. Jones; D. Hardt. IETF. 2012년 10월. 제안 표준. URL: https://www.rfc-editor.org/info/rfc6750/
[RFC7231]
하이퍼텍스트 전송 프로토콜(HTTP/1.1): 의미론 및 콘텐츠. R. Fielding, 편집; J. Reschke, 편집. IETF. 2014년 6월. 제안 표준. URL: https://httpwg.org/specs/rfc7231.html
[RFC7232]
하이퍼텍스트 전송 프로토콜(HTTP/1.1): 조건부 요청. R. Fielding, 편집; J. Reschke, 편집. IETF. 2014년 6월. 제안 표준. URL: https://httpwg.org/specs/rfc7232.html
[RFC7233]
하이퍼텍스트 전송 프로토콜(HTTP/1.1): 범위 요청. R. Fielding, 편집; Y. Lafon, 편집; J. Reschke, 편집. IETF. 2014년 6월. 제안 표준. URL: https://httpwg.org/specs/rfc7233.html
[RFC7240]
HTTP의 Prefer 헤더. J. Snell. IETF. 2014년 6월. 제안 표준. URL: https://www.rfc-editor.org/info/rfc7240/
[RFC7386]
JSON 병합 패치. P. Hoffman; J. Snell. IETF. 2014년 10월. 제안 표준. URL: https://www.rfc-editor.org/info/rfc7386/
[RFC8174]
RFC 2119 핵심 단어의 대문자와 소문자 사용에 따른 모호성. B. Leiba. IETF. 2017년 5월. 현행 최선의 관행. URL: https://www.rfc-editor.org/info/rfc8174/
[RFC8288]
웹 링크. M. Nottingham. IETF. 2017년 10월. 제안 표준. URL: https://httpwg.org/specs/rfc8288.html
[RFC8414]
OAuth 2.0 권한 부여 서버 메타데이터. M. Jones; N. Sakimura; J. Bradley. IETF. 2018년 6월. 제안 표준. URL: https://www.rfc-editor.org/info/rfc8414/
[RFC8693]
OAuth 2.0 토큰 교환. M. Jones; A. Nadalin; B. Campbell, 편집; J. Bradley; C. Mortimore. IETF. 2020년 1월. 제안 표준. URL: https://www.rfc-editor.org/info/rfc8693/
[RFC9068]
OAuth 2.0 접근 토큰을 위한 JSON 웹 토큰(JWT) 프로필. V. Bertocci. IETF. 2021년 10월. 제안 표준. URL: https://www.rfc-editor.org/info/rfc9068/
[RFC9110]
HTTP 의미론. R. Fielding, 편집; M. Nottingham, 편집; J. Reschke, 편집. IETF. 2022년 6월. 인터넷 표준. URL: https://httpwg.org/specs/rfc9110.html
[rfc9112]
HTTP/1.1. R. Fielding, 편집; M. Nottingham, 편집; J. Reschke, 편집. IETF. 2022년 6월. 인터넷 표준. URL: https://httpwg.org/specs/rfc9112.html
[RFC9264]
링크 집합: 링크 집합을 위한 미디어 유형 및 링크 관계 유형. E. Wilde; H. Van de Sompel. IETF. 2022년 7월. 제안 표준. URL: https://www.rfc-editor.org/info/rfc9264/
[RFC9457]
HTTP API를 위한 문제 세부 정보. M. Nottingham; E. Wilde; S. Dalal. IETF. 2023년 7월. 제안 표준. URL: https://www.rfc-editor.org/info/rfc9457/
[URL]
URL 표준. Anne van Kesteren. WHATWG. 현행 표준. URL: https://url.spec.whatwg.org/
[WebArch]
월드 와이드 웹 아키텍처, 제 1권. Ian Jacobs; Norman Walsh. W3C. 2004년 12월 15일. W3C 권고안. URL: https://www.w3.org/TR/webarch/
[XMLSCHEMA11-2]
W3C XML 스키마 정의 언어(XSD) 1.1 제2부: 데이터 유형. David Peterson; Sandy Gao; Ashok Malhotra; Michael Sperberg-McQueen; Henry Thompson; Paul V. Biron 외. W3C. 2012년 4월 5일. W3C 권고안. URL: https://www.w3.org/TR/xmlschema11-2/

B.2 정보성 참고문헌

[LDN]
연결된 데이터 알림. Sarven Capadisli; Amy Guy. W3C. 2017년 5월 2일. W3C 권고안. URL: https://www.w3.org/TR/ldn/
[RFC5785]
Well-Known URI(Uniform Resource Identifier) 정의. M. Nottingham; E. Hammer-Lahav. IETF. 2010년 4월. 제안 표준. URL: https://www.rfc-editor.org/info/rfc5785/
[RFC6125]
전송 계층 보안(TLS) 맥락에서 X.509(PKIX) 인증서를 사용한 인터넷 공개 키 인프라 내 도메인 기반 애플리케이션 서비스 신원의 표현 및 검증. P. Saint-Andre; J. Hodges. IETF. 2011년 3월. 제안 표준. URL: https://www.rfc-editor.org/info/rfc6125/
[RFC8259]
JavaScript 객체 표기법(JSON) 데이터 교환 형식. T. Bray, 편집. IETF. 2017년 12월. 인터넷 표준. URL: https://www.rfc-editor.org/info/rfc8259/
[RFC9325]
전송 계층 보안(TLS) 및 데이터그램 전송 계층 보안(DTLS)의 안전한 사용을 위한 권고 사항. Y. Sheffer; P. Saint-Andre; T. Fossati. IETF. 2022년 11월. 현행 최선의 관행. URL: https://www.rfc-editor.org/info/rfc9325/
[RFC9700]
OAuth 2.0 보안을 위한 현행 최선의 관행. T. Lodderstedt; J. Bradley; A. Labunets; D. Fett. IETF. 2025년 1월. 현행 최선의 관행. URL: https://www.rfc-editor.org/info/rfc9700/
[Solid-Protocol]
Solid 프로토콜. Sarven Capadisli; Tim Berners-Lee; Kjetil Kjernsmo. Solid 커뮤니티 그룹. 2024년 5월 12일. 커뮤니티 그룹 보고서 초안. URL: https://solidproject.org/TR/protocol