diff --git a/setup.sh b/setup.sh index d3d7dcc..fa63116 100755 --- a/setup.sh +++ b/setup.sh @@ -5,5 +5,11 @@ # pipx install bikeshed # bikeshed update (to get the latest autolinking data) -for bsdoc in ./*.bs ./**/*.bs; do bikeshed spec $bsdoc; done -for diagram in primer/*.mmd; do docker run --rm -v "$PWD:/data" minlag/mermaid-cli -i /data/$diagram; done +# Enable recursive globbing for ** +shopt -s globstar + +# 1. Generate ALL diagrams +for diagram in ./*.mmd ./**/*.mmd; do [ -f "$diagram" ] && docker run --rm -u $(id -u):$(id -g) -v "$PWD:/data" minlag/mermaid-cli -i "/data/$diagram"; done + +# 2. Build ALL specs +for bsdoc in ./*.bs ./**/*.bs; do [ -f "$bsdoc" ] && bikeshed spec "$bsdoc"; done \ No newline at end of file diff --git a/snapshot-gat/README.md b/snapshot-gat/README.md new file mode 100644 index 0000000..af63b05 --- /dev/null +++ b/snapshot-gat/README.md @@ -0,0 +1,6 @@ +# Solid-OIDC: Global Access Token (GAT) Snapshot + +Addresses https://github.com/solid/solid-oidc/issues/250 and captures the authentication flow that all current server and client implementations support (as of 2026-04-21). + +This specification version is a snapshot of Solid-OIDC, where a Client uses a global DPOP-bound access token issued by an OpenID Provider to authenticate at an Resource Server. + diff --git a/snapshot-gat/index.bs b/snapshot-gat/index.bs new file mode 100644 index 0000000..7e1e2c5 --- /dev/null +++ b/snapshot-gat/index.bs @@ -0,0 +1,692 @@ +
+Title: Solid-OIDC: Global Access Token (GAT) Snapshot +Boilerplate: issues-index no +Shortname: solid-oidc-gat +Level: 1 +Status: CG-DRAFT +Group: solidcg +ED: https://solid.github.io/solid-oidc/ +TR: https://solidproject.org/TR/oidc +!Created: July 16, 2021 +!Modified: [DATE] +Repository: https://github.com/solid/solid-oidc +Inline Github Issues: title +Markup Shorthands: markdown yes +Max ToC Depth: 2 +Editor: Aaron Coburn, Inrupt, https://people.apache.org/~acoburn/#i +Editor: elf Pavlik, , https://elf-pavlik.hackers4peace.net +Editor: Christoph Braun, Forschungszentrum Informatik (FZI) +Former Editor: Dmitri Zagidulin, , http://computingjoy.com/ +Former Editor: Adam Migus, The Migus Group, https://migusgroup.com/about/ +Former Editor: Ricky White, The Migus Group, https://rickywhite.net +Test Suite: https://solid-contrib.github.io/solid-oidc-tests/ +Metadata Order: This version, Latest published version, Test Suite, Created, Modified, *, !* +Abstract: + The Solid OpenID Connect (Solid-OIDC) specification defines how resource servers + verify the identity of relying parties and end users based on the authentication + performed by an OpenID provider. Solid-OIDC builds on top of OpenID Connect 1.0 + for use within the Solid ecosystem. + + This version is a snapshot of Solid-OIDC, where a Client uses a global DPOP-bound access token + issued by an OpenID Provider to authenticate at an Resource Server. ++ +# Introduction # {#intro} + +*This section is non-normative* + +The [Solid project](https://solidproject.org/) aims to change the way web applications work today to +improve privacy and user control of personal data by utilizing current standards, protocols, and +tools, to facilitate building extensible and modular decentralized applications based on +[Linked Data](https://www.w3.org/standards/semanticweb/data) principles. + +This specification is written for Authorization and Resource Server owners intending to implement +Solid-OIDC. It is also useful to Solid application developers charged with implementing a Solid-OIDC +client. + +The OAuth 2.0 [[!RFC6749]] and OpenID Connect Core 1.0 [[!OIDC-CORE]] web standards were +published in October 2012 and November 2014, respectively. Since publication they've seen rapid and +widespread adoption across the industry, in turn gaining extensive *"real-world"* data and +experience. The strengths of the protocols are now clear; however, in a changing eco-system where +privacy and control of digital identities are becoming more pressing concerns, it is also clear +that additional functionality is required. + +The additional functionality documented herein aims to address: + +1. Resource servers having no existing trust relationship with identity providers. +2. Ephemeral Clients as a first-order use-case. + +
+ This version is a snapshot of Solid-OIDC, where a Client uses a global DPOP-bound access token + issued by an OpenID Provider to authenticate at an Resource Server. +
+https://app.example/id
+ +
+ {
+ "@context": ["https://www.w3.org/ns/solid/oidc-context.jsonld"],
+
+ "client_id": "https://app.example/id",
+ "client_name": "Solid Application Name",
+ "redirect_uris": ["https://app.example/callback"],
+ "post_logout_redirect_uris": ["https://app.example/logout"],
+ "client_uri": "https://app.example/",
+ "logo_uri" : "https://app.example/logo.png",
+ "tos_uri" : "https://app.example/tos.html",
+ "scope" : "openid profile offline_access webid",
+ "grant_types" : ["refresh_token","authorization_code"],
+ "response_types" : ["code"],
+ "default_max_age" : 3600,
+ "require_auth_time" : true
+ }
+
+
+ {
+ "client_name": "S-C-A Browser Demo Client App",
+ "application_type": "web",
+ "redirect_uris": [
+ "https://dynamic-client.example/auth"
+ ],
+ "subject_type": "pairwise",
+ "token_endpoint_auth_method": "client_secret_basic",
+ "scope" : "openid profile offline_access webid"
+ }
+
++ PREFIX solid: <http://www.w3.org/ns/solid/terms#> + + <#id> solid:oidcIssuer <https://oidc.example> . ++
+ ?webid <http://www.w3.org/ns/solid/terms#oidcIssuer> ?iss . ++where `?webid` is set to WebID. The `?iss` will result in an IRI denoting valid issuer for that WebID. +The WebID Profile Document MUST include one or more statements matching the OIDC issuer pattern. + +Issue(80): + +Issue(92): + +Issue(91): + +### OIDC Issuer Discovery via Link Headers ### {#oidc-issuer-discovery-link-headers} + +A server hosting a WebID Profile Document MAY transmit the `http://www.w3.org/ns/solid/terms#oidcIssuer` +values via Link Headers, but they MUST be the same as in the RDF representation. +A client MUST treat the RDF in the body of the WebID Profile as canonical +but MAY use the Link Header values as an optimization. + +
+ Link: <https://oidc.example>; + rel="http://www.w3.org/ns/solid/terms#oidcIssuer"; + anchor="#id" ++
+HTTP/1.1 302 Found +Location: https://client.example.com/callback? + code=n0esc392ae491076 + &state=af0ifjsldkj + &iss=https%3A%2F%2Fidp.example.com ++
+ This version of Solid-OIDC relies on a global DPOP-bound access token issued by the OpenID Provider (OP) to authenticate a Client at a Resource Server (RS). +
++ Solid-OIDC 0.1.0 relies the concept of Authorization Servers (AS) that manage access to the Resource Servers under their authority ("realm"). + To access data provided by an RS, a Client needs to obtain an access token issued by the AS that the RS is overseen by. + To obtain such an access token, the Client needs to successfully authenticating at and be indeed authorized by the AS to access the desired data. + To authenticate at the AS, the Client presents the OIDC ID token obtained from their OP. +
++ Solid-OIDC 0.1.0 thus mandates: +
An example DPoP-bound Access Token: + +
+ {
+ "webid": "https://janedoe.com/web#id",
+ "sub": "https://janedoe.com/web#id"
+ "client_id": "https://client.example.com/web#id"
+ "iss": "https://idp.example.com",
+ "aud": "solid",
+ "iat": 1541493724,
+ "exp": 1573029723,
+ "cnf":{
+ "jkt":"0ZcOCORZNYy-DWpqq30jZyJGHTN0d2HglBV3uiguA4I"
+ },
+ }
+
+An example OIDC ID Token: + +
+ {
+ "webid": "https://janedoe.com/web#id",
+ "sub": "https://janedoe.com/web#id",
+ "azp": "https://client.example.com/web#id",
+ "iss": "https://idp.example.com",
+ "aud": ["https://client.example.com/web#id","solid"],
+ "nonce": "n-0S6_WzA2Mj",
+ "exp": 1311281970,
+ "iat": 1311280970,
+ }
+
+401 status code,
+and a WWW-Authenticate HTTP header. See also: [[RFC9110]](11.6.1. WWW-Authenticate)
+
+When a Client performs an authenticated request, i.e., using the DPOP-bound access token issued by the OP and a self-issued DPOP token, the Resource Server MUST perform [[#dpop-validation]] and [[#token-validation]].
+
+
+## DPoP Validation ## {#dpop-validation}
+
+A DPoP Proof that is valid according to
+[RFC9449](https://datatracker.ietf.org/doc/html/rfc9449#section-4.3),
+MUST be present when a DPoP-bound Access Token is used.
+
+The DPoP-bound Access Token MUST be validated according to
+[RFC9449](https://datatracker.ietf.org/doc/html/rfc9449#section-6),
+but the RS MAY perform additional verification in order to determine whether to grant access to the
+requested resource.
+
+# Solid-OIDC Conformance Discovery # {#discovery}
+
+An OpenID Provider that conforms to the Solid-OIDC specification MUST advertise it in the OpenID Connect
+Discovery 1.0 [[!OIDC-DISCOVERY]] resource by including `webid` in its `scopes_supported` metadata property.
+
+
+ {
+ "scopes_supported": ["openid", "offline_access", "webid"]
+ }
+
+
+ {
+ "@context": {
+ "@version": 1.1,
+ "@protected": true,
+ "oidc": "http://www.w3.org/ns/solid/oidc#",
+ "xsd": "http://www.w3.org/2001/XMLSchema#",
+ "client_id": {
+ "@id": "@id",
+ "@type": "@id"
+ },
+ "client_uri": {
+ "@id": "oidc:client_uri",
+ "@type": "@id"
+ },
+ "logo_uri": {
+ "@id": "oidc:logo_uri",
+ "@type": "@id"
+ },
+ "policy_uri": {
+ "@id": "oidc:policy_uri",
+ "@type": "@id"
+ },
+ "tos_uri": {
+ "@id": "oidc:tos_uri",
+ "@type": "@id"
+ },
+ "redirect_uris": {
+ "@id": "oidc:redirect_uris",
+ "@type": "@id",
+ "@container": [
+ "@id",
+ "@set"
+ ]
+ },
+ "require_auth_time": {
+ "@id": "oidc:require_auth_time",
+ "@type": "xsd:boolean"
+ },
+ "default_max_age": {
+ "@id": "oidc:default_max_age",
+ "@type": "xsd:integer"
+ },
+ "application_type": {
+ "@id": "oidc:application_type"
+ },
+ "client_name": {
+ "@id": "oidc:client_name"
+ },
+ "contacts": {
+ "@id": "oidc:contacts"
+ },
+ "grant_types": {
+ "@id": "oidc:grant_types"
+ },
+ "response_types": {
+ "@id": "oidc:response_types"
+ },
+ "scope": {
+ "@id": "oidc:scope"
+ },
+ "token_endpoint_auth_method": {
+ "@id": "oidc:token_endpoint_auth_method"
+ }
+ }
+ }
+
+
+
+{
+ "DPOP": {
+ "authors": [
+ "D. Fett",
+ "B. Campbell",
+ "J. Bradley",
+ "T. Lodderstedt",
+ "M. Jones",
+ "D. Waite"
+ ],
+ "href": "https://datatracker.ietf.org/doc/html/rfc9449",
+ "title": "OAuth 2.0 Demonstration of Proof-of-Possession at the Application Layer (DPoP)",
+ "publisher": "IETF"
+ },
+ "OIDC-CORE": {
+ "authors": [
+ "N. Sakimura",
+ "J. Bradley",
+ "M. Jones",
+ "B. de Medeiros",
+ "C. Mortimore"
+ ],
+ "href": "https://openid.net/specs/openid-connect-core-1_0.html",
+ "title": "OpenID Connect Core 1.0",
+ "publisher": "The OpenID Foundation"
+ },
+ "OIDC-DISCOVERY": {
+ "authors": [
+ "N. Sakimura",
+ "J. Bradley",
+ "M. Jones",
+ "E. Jay"
+ ],
+ "href": "https://openid.net/specs/openid-connect-discovery-1_0.html",
+ "title": "OpenID Connect Discovery 1.0",
+ "publisher": "The OpenID Foundation"
+ },
+ "OIDC-DYNAMIC-CLIENT-REGISTRATION": {
+ "authors": [
+ "N. Sakimura",
+ "J. Bradley",
+ "M.B. Jones"
+ ],
+ "href": "https://openid.net/specs/openid-connect-registration-1_0.html",
+ "title": "OpenID Connect Dynamic Client Registration 1.0",
+ "publisher": "The OpenID Foundation"
+ },
+ "SOLID-PROTOCOL": {
+ "authors": [
+ "Sarven Capadisli",
+ "Tim Berners-Lee",
+ "Ruben Verborgh",
+ "Kjetil Kjernsmo",
+ "Justin Bingham",
+ "Dmitri Zagidulin"
+ ],
+ "href": "https://solidproject.org/TR/protocol",
+ "title": "Solid Protocol",
+ "publisher": "W3C Solid Community Group"
+ },
+ "SOLID-OIDC-PRIMER": {
+ "authors": [
+ "Jackson Morgan",
+ "Aaron Coburn",
+ "Matthieu Bosquet"
+ ],
+ "href": "https://solid.github.io/solid-oidc/primer/",
+ "title": "Solid-OIDC Primer",
+ "publisher": "W3C Solid Community Group"
+ },
+ "WEBID": {
+ "authors": [
+ "Andrei Sambra",
+ "Henry Story",
+ "Tim Berners-Lee"
+ ],
+ "href": "https://www.w3.org/2005/Incubator/webid/spec/identity/",
+ "title": "WebID 1.0",
+ "publisher": "WebID Incubator Group"
+ },
+ "BCP195": {
+ "href": "https://www.rfc-editor.org/info/bcp195",
+ "title": "Best Current Practice 195",
+ "publisher": "IETF"
+ }
+}
+
\ No newline at end of file
diff --git a/snapshot-gat/sequence-gat.mmd b/snapshot-gat/sequence-gat.mmd
new file mode 100644
index 0000000..9c6935a
--- /dev/null
+++ b/snapshot-gat/sequence-gat.mmd
@@ -0,0 +1,30 @@
+sequenceDiagram
+ participant WebID as 👩 End-User's WebID Document
+ participant OP as 👩 OpenID Provider
+ participant ClientID as ⚙️ Client's ID Document
+ participant C as ⚙️ Client
+ participant RS as ☁️ Resource Server
+
+ C ->> RS: unauthenticated request
+ RS ->> C: 401 with a WWW-Authenticate HTTP header
+ Note over C: 👩 User provides their WebID ⌨️
+ C ->> WebID: get WebID document to discover OpenID Provider
+ WebID ->> C: WebID document
+ C ->> OP: start Authorization Code grant
+ OP->> ClientID: get Client ID document
+ ClientID->> OP: ClientID document
+ Note over OP: compare redirect_uri
+ OP ->> C: return Authorization Code
+ C ->> OP: present Authorization Code and DPoP proof
+ Note over OP: ⚙️ Client is authenticated ✅
+ OP ->> C: return DPoP bound Access Token and OIDC ID Token
+ Note over C: ⚙️ Client validates OP
+ Note over C: 👩 User is authenticated ✅
+ C ->> RS: request with DPOP-bound Access Token and DPoP Token
+ RS ->> WebID: get WebID document to verify OpenID Provider
+ WebID ->> RS: WebID document
+ RS ->> OP: get OP's public key to verify ID Token (JWS)
+ OP ->> RS: JWKS
+Note over RS: ☁️ RS verify DPoP-bound Access Token and DPoP Token
+ Note over RS: 👩 User and ⚙️ Client are authenticated ✅
+ RS ->> C: resource representation