{"id":13556518,"url":"https://github.com/solid/webid-oidc-spec","last_synced_at":"2025-04-03T10:30:47.246Z","repository":{"id":48374383,"uuid":"88293864","full_name":"solid/webid-oidc-spec","owner":"solid","description":"WebID-OIDC Authentication Spec v0.1.0","archived":true,"fork":false,"pushed_at":"2021-07-29T16:26:34.000Z","size":370,"stargazers_count":56,"open_issues_count":27,"forks_count":18,"subscribers_count":26,"default_branch":"master","last_synced_at":"2024-11-04T06:34:54.424Z","etag":null,"topics":["specification"],"latest_commit_sha":null,"homepage":"","language":null,"has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/solid.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2017-04-14T18:47:03.000Z","updated_at":"2024-07-12T11:34:51.000Z","dependencies_parsed_at":"2022-09-21T17:03:47.195Z","dependency_job_id":null,"html_url":"https://github.com/solid/webid-oidc-spec","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/solid%2Fwebid-oidc-spec","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/solid%2Fwebid-oidc-spec/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/solid%2Fwebid-oidc-spec/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/solid%2Fwebid-oidc-spec/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/solid","download_url":"https://codeload.github.com/solid/webid-oidc-spec/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":246984447,"owners_count":20864443,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["specification"],"created_at":"2024-08-01T12:03:53.149Z","updated_at":"2025-04-03T10:30:46.933Z","avatar_url":"https://github.com/solid.png","language":null,"readme":"# WebID-OIDC Authentication Spec\n[![](https://img.shields.io/badge/project-Solid-7C4DFF.svg?style=flat-square)](https://github.com/solid/solid)\n\n**Current Spec version:** `v.0.1.0` (see [CHANGELOG.md](CHANGELOG.md))\n\nWebID-OIDC is an authentication delegation protocol (as well as a toolkit of\nuseful auth-related verification techniques) suitable for WebID-based\ndecentralized systems such as [Solid](https://github.com/solid/solid), as well\nas most LDP-based systems. It is based on decentralized OAuth2/OpenID Connect.\n\n## Table of Contents\n\n* [Introduction](#introduction)\n    - [Benefits and Capabilities](#benefits-and-capabilities)\n    - [If You're Unfamiliar with OIDC](#if-youre-unfamiliar-with-oidc)\n* [Differences from Classic OpenID Connect](#differences-from-classic-openid-connect)\n* [Brief Workflow Summary](#brief-workflow-summary)\n* [Deriving WebID URI from ID Token](#deriving-webid-uri-from-id-token)\n* [WebID Provider Confirmation](#webid-provider-confirmation)\n* [Authorized OIDC Issuer Discovery](#authorized-oidc-issuer-discovery)\n    - [Issuer Discovery From Link Header](#issuer-discovery-from-link-header)\n    - [Issuer Discovery From WebID Profile](#issuer-discovery-from-webid-profile)\n* [Detailed Sign In Workflow Example](#detailed-sign-in-workflow-example)\n* [Workflow Example for Tokens Representing the App Itself](#detailed-app-centric-workflow)\n* [Workflow Example for Tokens Representing a User via App Itesef](#detailed-user-app-centric-workflow)\n* [Decentralized Authentication Glossary](#decentralized-authentication-glossary)\n\n## Introduction\n\nThe end result of any WebID-based authentication workflow is a verified WebID\nURI (specifically, the recipient verifies that the agent controls that URI).\nFor example,\n[WebID-TLS](https://github.com/solid/solid-spec/blob/master/authn-webid-tls.md)\nderives the WebID URI from a TLS certificate, and verifies the certificate\nagainst the public key in an agent's WebID Profile. Similarly, the end result of\n[OpenID Connect (OIDC)](https://openid.net/specs/openid-connect-core-1_0.html)\nworkflows is a verified ID Token. The WebID-OIDC protocol specifies a mechanism\nfor getting a WebID URI from an OIDC ID Token, and gains the benefits of both\nthe decentralized flexibility of WebID, and the field-proven security of OpenID\nConnect.\n\nSee also: [Motivation for WebID-OIDC](motivation.md).\n\n### Benefits and Capabilities\n\n* Fully decentralized cross-domain authentication (any peer node can serve as\n  an identity provider as well as a relying party to any other node) made possible by\n  [Proof of Posession (PoP) Tokens](https://tools.ietf.org/html/rfc7800).\n* Builds on decades of real-world authentication industry experience\n* Incorporates lessons from, and fixes to threat models of: SAML, OpenID and\n  OpenID 2, OAuth and OAuth 2. See, for example, [RFC 6819 - OAuth 2.0 Threat\n  Model and Security\n  Considerations](http://tools.ietf.org/html/rfc6819) -- OpenID Connect was\n  developed in large part to address the threats outlined there.\n* Stands on the shoulders of giants (makes use of the JOSE suite of standards\n  for token representation, cryptographic signing and encryption,\n  including [JWT](https://tools.ietf.org/html/rfc7519),\n  [JWA](https://tools.ietf.org/html/rfc7518),\n  [JWE](https://tools.ietf.org/html/rfc7516) and\n  [JWS](https://tools.ietf.org/html/rfc7515))\n* Sign Off (and Single Sign Off) capability\n* Capability for [revocations](https://tools.ietf.org/html/rfc7009), black\n  lists and white lists of both providers and client apps\n* Supports authentication for the full range of agents and clients: in-browser\n  Javascript apps, traditional server-side web apps, mobile and desktop apps,\n  and IoT devices.\n* Compatibility with existing [Web Access\n  Control](https://github.com/solid/web-access-control-spec) ACL implementations\n  such as those in Solid servers.\n* Sets up the infrastructure for adding Capabilities functionality to Solid\n\n### If You're Unfamiliar with OIDC\n\nIf you're not familiar with the OIDC/OAuth2 workflow, you should do the\nfollowing:\n\n * Read the [Brief Workflow Summary](#brief-workflow-summary) section below\n * Refer to the [Decentralized Authentication\n   Glossary](#decentralized-authentication-glossary) to help clarify how the\n   various terms (Relying Party, Provider, etc) apply to WebID systems.\n * Read the [OpenID Connect\n   explained](http://connect2id.com/learn/openid-connect)\n   article. Becoming familiar with the basic OIDC concepts will be quite\n   helpful with understanding this spec.\n\n## Differences from Classic OpenID Connect\n\nWebID-OIDC makes the following changes to the base OpenID Connect protocol\n(which itself improves and builds on OAuth 2):\n\n* Discusses and formalizes the [Provider\n  Selection](example-workflow.md#21-provider-selection) step.\n* Adds a procedure for [Deriving a WebID URI from ID\n  Token](#deriving-webid-uri-from-id-token), since WebID-based protocols use\n  the WebID URI as a globally unique identifier (rather than the combination of\n  `iss`uer and `sub`ject claims).\n* Adds an additional step: [WebID Provider\n  Confirmation](#webid-provider-confirmation).\n  After the WebID URI is extracted, the recipient of the ID Token must confirm\n  that the Provider was indeed authorized by the holder of the WebID profile.\n* Specifies the [Authorized OIDC Issuer\n  Discovery](#authorized-oidc-issuer-discovery) process (used as part of\n  Provider Confirmation, and during Provider Selection steps).\n* Utilizes [PoP tokens](https://tools.ietf.org/html/rfc7800) as a means to\n  access a wide array of resource providers.\n\nIt's also worth mentioning that while traditional OpenID Connect use cases are\nconcerned with retrieving user-related claims from [UserInfo\nendpoints](https://openid.net/specs/openid-connect-core-1_0.html#UserInfo), most\nWebID based systems replace the UserInfo mechanism with the contents of\n[WebID Profile](https://github.com/solid/solid-spec#webid-profile-documents)\ndocuments.\n\n## Brief Workflow Summary\n\nThe overall sign in workflow used by the WebID-OIDC protocol is as follows.\nFor example, here is what happens when Alice tries to request the resource\n`https://bob.example/resource1`.\n\n1. [Initial Request](example-workflow.md#1-initial-request): Alice\n   (unauthenticated) makes a request to `bob.example`, receives an HTTP `401\n   Unauthorized` response, and is presented with a 'Sign In With...' screen.\n2. [Provider Selection](example-workflow.md#21-provider-selection): She selects\n   her WebID service provider by clicking on a logo, typing in a URI (for\n   example, `alice.solidtest.space`), or entering her email.\n3. [Local\n   Authentication](example-workflow.md#3-local-authentication-to-provider):\n   Alice gets redirected towards her service provider's own Sign In page, thus requesting\n   `https://alice.solidtest.space/signin`, and authenticates using her preferred\n   method (password, WebID-TLS certificate, FIDO 2 /\n   [WebAuthn](https://w3c.github.io/webauthn/) device, etc).\n4. [User Consent](example-workflow.md#4-user-consent): (Optional) She'd also be\n   presented with a user consent screen, along the lines of \"Do you wish to\n   sign in to `bob.example`?\".\n5. [Authentication Response](example-workflow.md#5-authentication-response):\n   She then gets redirected back towards `https://bob.example/resource1` (the\n   resource she was originally trying to request). The server, `bob.example`, also\n   receives a signed ID Token from `alice.solidtest.space` that was returned\n   with the response in point 3, attesting that she has signed in.\n6. [Deriving a WebID URI](#deriving-webid-uri-from-id-token):\n   `bob.example` (the server controlling the resource) validates the ID Token, and\n   extracts Alice's WebID URI from inside  it. She is now signed in to\n   `bob.example` as user `https://alice.solidtest.space/#i`.\n7. [WebID Provider Confirmation](#webid-provider-confirmation):\n   `bob.example` confirms that `solidtest.space` is indeed Alice's authorized OIDC\n   provider (by matching the provider URI from the `iss` claim with Alice's\n   WebID).\n\nThere is a lot of heavy lifting happening under the hood, performed by `bob.example`\nand `alice.solidtest.space`, the two servers involved in this exchange. They\nestablish a trust relationship with each other (via\n[Discovery](example-workflow.md#22-provider-discovery), and [Dynamic\nRegistration](example-workflow.md#23-dynamic-client-registration-first-time-only)),\nthey verify each other's signatures against their public keys, and verify\nAlice's client app (if she's using one). Fortunately, all of that complexity is\nhidden from the user (and most of it is also hidden from the app developer).\n\n## Deriving WebID URI from ID Token\n\nA WebID-OIDC conforming Relying Party tries the following methods, in order, to\nobtain a WebID URI from an ID Token:\n\n##### Method 1 - Custom `webid` claim\n\nFirst, check the ID Token payload for the `webid` claim. This claim is added to\nthe set of [OpenID Connect ID\nToken](https://openid.net/specs/openid-connect-core-1_0.html#IDToken) claims by\nthis WebID-OIDC spec. (Note that the set of ID Token claims is extensible, by\ndesign, as explained in the OIDC Core spec.) If the `webid` claim is present in\nthe ID Token, its value should be used as the WebID URI by the Relying Party,\ninstead of the traditional `sub` (subject identifier) claim.\n\nThis method is useful when the identity providers issuing the tokens can\ncustomize the contents of their ID tokens (and can add the `webid` claim).\n\n##### Method 2 - Value of `sub` claim contains a valid HTTP(S) URI\n\nIf the `webid` claim is not present in the ID Token, the Relying Party should\ncheck if the `sub` claim contains as its value a valid HTTP(S) URI. If the value\nof the `sub`ject claim is a valid URI, it should be used as the WebID URI by the\nRelying Party.\n\nThis method is useful when the identity providers issuing the tokens cannot add\nclaims but can set their own values of their `sub`ject claims (that is, they're\nnot automatically generated as UUIDs, etc).\n\n##### Method 3 - UserInfo request + `website` claim\n\nIf a WebID URI is not found in either the `webid` or `sub` claim, the Relying\nParty should proceed to make an OpenID Connect [UserInfo\nRequest](https://openid.net/specs/openid-connect-core-1_0.html#UserInfo), with\nthe appropriate Access Token that it received alongside the ID Token. This\nmethod is provided for cases where users do not have control over the contents\nof the ID Tokens issued by their Providers and so would not be able to use the\nprevious methods. This would be the case, for example, if a user wanted to sign\nin to a WebID-OIDC Relying Party using an existing mainstream Provider such as\nGoogle. Once the UserInfo response is received by the Relying Party, the\nstandard `website` claim should be used as the WebID URI by that RP.\n\n## WebID Provider Confirmation\n\n#### The Problem\n\nThe OIDC spec uses the ID Token's `sub`ject claim as a unique user id. However,\nit requires that the id is unique *for a given Provider*. Given that a WebID\nis a *globally* unique user identifier, the WebID-OIDC protocol needs to take\nan additional step and *confirm* that the holder of that WebID has authorized\na given Provider to use that WebID. Otherwise, the following situation can\nhappen:\n\n1. Alice logs in to `bob.example` with her identity Provider of choice, `alice.example`.\n   The ID Token from `alice.example` claims Alice's WebID is\n   `https://alice.example/#i`. So far so good.\n2. An attacker also logs in to `bob.example`, using `evilbox.com` as an identity\n   Provider. And because they happen to control that server, they can put\n   anything they want in the `webid` claim of any ID Token coming out of that\n   server. So they *also* claim that their `webid` is `https://alice.example/#i`.\n\nWithout an additional confirmation step, how can a recipient of an ID Token\n(here, `bob.example`) know which of those login attempts is correct? To put it\nanother way, how can a recipient know which Provider is *approved* by the\nowner of the WebID?\n\n#### The Solution\n\nWhen presented with WebID-OIDC credentials in the form of bearer tokens,\nthe Resource Server MUST confirm that the Identity Provider (the value in the\n`iss`uer claim) is authorized by the holder of the WebID, by doing the\nfollowing:\n\n1. (Common case) If the server that issued the ID Token is the same entity that\n  hosts the WebID profile, then it is considered the authorized OIDC provider\n  for that WebID (short-circuiting the Provider Confirmation process), and no\n  further steps need to be taken. Specifically, one of the following must be\n  true:\n    - The [origin](https://developer.mozilla.org/en-US/docs/Web/API/URL/origin)\n      of the WebID URI is the same as the origin of the URI in the\n      `iss`uer claim. (For example, `iss: 'https://example.com'` and the\n      WebID URI is `https://example.com/profile#me`).\n    - The WebID URI is a *subdomain* of the issuer of the ID Token.\n      For example, `iss: 'https://example.com'` and the WebID URI is\n      `https://alice.example.com/profile#me`.\n   If neither of the above is the case (and the WebID is hosted on a security\n   realm different than that of its OIDC provider), further steps need to be\n   taken for confirmation.\n2. Determine the **authorized OIDC provider** URI for that WebID, by performing\n   [Authorized OIDC Issuer Discovery](#authorized-oidc-issuer-discovery).\n3. If the Provider URI is not discoverable (either from the header or the body\n   of the [WebID\n   Profile](https://github.com/solid/solid-spec#webid-profile-documents), the Resource Server MUST reject the credentials or authentication attempt.\n4. If the Provider URI is discovered, it MUST match the Issuer URI in the ID\n   Token (the `iss` claim), reject the credentials otherwise.\n\n## Authorized OIDC Issuer Discovery\n\nDuring the Provider Selection or [Provider\nConfirmation](#webid-provider-confirmation) steps it is necessary to discover,\nfor a given WebID, the URI of the authorized OIDC provider for that WebID.\n\n1. First, attempt to [discover from link\n   headers](#issuer-discovery-from-link-header)\n2. If not found, proceed to [discover from the WebID\n   Profile](#issuer-discovery-from-webid-profile)\n\nNote that this procedure is different from the classic [OpenID Provider Issuer\nDiscovery](https://openid.net/specs/openid-connect-discovery-1_0.html#IssuerDiscovery)\nprocess, since that spec is concerned with discovering the issuer URI *from a\nuser's email address*, using the WebFinger protocol. Whereas this spec needs to\nderive the issuer URI from a WebID URI (which is often hosted on a different\ndomain than the issuer).\n\n#### Issuer Discovery From Link Header\n\n**Note: this feature is at risk of being removed.\nPlease [join the discussion](https://github.com/solid/webid-oidc-spec/issues/18).\nCode depending on this will still work for now.**\n\nTo discover the authorized OIDC Issuer for a given WebID from Link rel headers:\n\n1. Make an HTTP OPTION request to the WebID URI.\n2. Parse the `Link:` header, and check for the value of the\n  `http://openid.net/specs/connect/1.0/issuer` link relation. If\n  present, use the value of that link relation as the authorized Provider\n  URI. For example: `Link: \u003chttps://provider.example.com\u003e; rel=\"http://openid.net/specs/connect/1.0/issuer\"` means that `https://provider.example.com` is the authorized OIDC provider for that URI.\n3. If the Link header is not present (or does not contain the relevant link\n   relation), proceed to discovering the issuer from the WebID profile contents.\n\n#### Issuer Discovery From WebID Profile\n\nTo discover the authorized OIDC Issuer for a given WebID from the WebID Profile\ncontents (this requires Turtle/RDF parsing capability):\n\n1. Dereference the WebID URI (make an HTTP GET request) and fetch the contents\n  of the WebID Profile (typically in Turtle or JSON-LD format or some other RDF\n  serialization).\n2. Parse the RDF, and query for the object of the statement containing the\n  `\u003chttp://www.w3.org/ns/solid/terms#oidcIssuer\u003e` predicate.\n\nFor example, if Alice (with the WebID of `https://alice.example.com/profile#me`)\nwanted to specify `https://provider.com` as the authorized OIDC provider for\nthat profile, she would add the following triple to her profile:\n\n```ttl\n@prefix solid: \u003chttp://www.w3.org/ns/solid/terms#\u003e.\n\n# ...\n\n\u003c#me\u003e solid:oidcIssuer \u003chttps://provider.com\u003e .\n```\n\n## Securing tokens for multiple resource servers\n\n#### The Problem\n\nWebID-OIDC must deal with a number of RSs many of which the OP will not know about. OIDC defines the `aud` claim which defines the RSs for which a token can be used.\n\nHowever, given Solid's use case, a token should be usable for any RS so the user may federate a query across multiple Pods, so the `aud`ience cannot be constrained. Yet, an unconstrained `aud`ience opens up the possibility of token stealing. In this case, a user sends a request to `evilPod.example`. The Pod returns the requested information, but now has the user's token and may pretend to be the user on any other Pod in the world.\n\n#### The Solution\n\nThe solution employs [Proof of Possession (PoP) tokens](https://tools.ietf.org/html/rfc7800) changing the way the Bearer token is constructed:\n\n 1. A client application generates a short-lived public and private key.\n 2. The client generates a request `JWT` just as it would under normal OIDC with the addition of a `key` field containing the public key.\n 3. Authentication proceeds normally and yields a signed `id_token` where the `aud`ience is the client application (represented by the `origin` of the provided `redirect_uri`) and an additional field `cnf` is provided containing the client's public key.\n 4. Before sending requests to any RSs, the client generates a new signed JWT PoP token containing the RS's uri as the `aud`ience and an `id_token` feild containing the `id_token` provided by the OP.\n 5. When an RS receives the PoP token, it MUST reject any tokens containing a mismatched audience or a signature that is not associated with the public key in the `cnf` claim.\n\n## Detailed Sign In Workflow Example\n\nTo walk through a more detailed example for WebID-OIDC login, refer to the\n[Example WebID-OIDC Workflow](example-workflow.md) doc.\n\n## Detailed App Centric Workflow\n\nFor a detailed example of how an application/agent can access resources in a\npod on behalf of a given user, refer to the\n[Example Application OIDC Workflow](application-workflow.md).\n\n## Detailed App User Centric Workflow\n\nFor a detailed example of how an application/agent can gain a token representing\nthe user via the application, refer to the\n[Example Application User OIDC Workflow](application-user-workflow.md).\n\n## Decentralized Authentication Glossary\n\nIn order to discuss decentralized authentication protocol details, it would be\nhelpful to familiarize ourselves with the terminology that is frequently used\nby various decentralized protocol specs (such as OAuth2, OpenID Connect).\n\n##### User\nHuman user. If the user is an app or service (that has its own WebID Profile),\nthis can be generalized to `Agent`. Also called `Resource Owner`. In the\nfollowing examples, Alice and Bob are Users.\n\n##### User-Agent\nA formal name for a `Browser`. Note that this is often separate from a Client\napplication (in many cases, client apps written in Javascript run *inside* the\nbrowser).\n\n##### Identity Provider (OP)\nAn OpenID Connect Identity `Provider` (called `OP` in most OIDC specs). Also\nsometimes referred to as `Issuer`. This can be either a POD (see below) or an\nexternal OIDC provider such as\n[Google](https://developers.google.com/identity/protocols/OpenIDConnect). In\nthe spec, Alice's POD, `alice.example`, will mostly play the role of a Provider.\n\n##### Resource Server (RS)\nA server hosting resources that the user wants to access, such as HTML, images,\nLinked Data / RDF sources, and so on. In the spec, `bob.example` will be used as\nthe `Resource Server` (that is, Alice will be requesting resources on Bob's\nserver). *Note:* In the traditional federated social sign on context, a\nprovider (such as Facebook) serves as *both* an Identity Provider *and* a\nResource Server.\n\n##### Relying Party (RP)\nA `Relying Party` is a POD or a client app that has to *rely* on an ID Token\nthat's issued by a Provider. In the spec, when Alice tries to access a resource\non `bob.example`, Bob's POD acts as the Relying Party, in that interaction.\nAnd correspondingly, Alice's POD, `alice.example`, will serve as the Identity\nProvider, again for that interaction.\n\nIncidentally, when Alice tries to access a resource on her *own* POD,\n`alice.example` plays all of the roles -- it's both the Provider and a Relying\nParty (as well as the Resource Server).\n\n##### POD\nA Personal Online Datastore (POD for short). It plays several roles -- firstly,\nit stores a user's data (and so acts as a `Resource Server`). In many cases, it\nalso hosts the user's WebID Profile, and implements the API endpoints that allow\nit to act as a WebID-OIDC Identity Provider (OP). Lastly, when users requests\nresources from it, the POD also acts as a Relying Party (a recipient of those\nusers' ID Tokens).\nIn this spec, `alice.example` and `bob.example` are both PODs.\n\n##### Home POD vs Other POD\nA user's Home POD is one that hosts their WebID Profile, and also acts as that\nuser's Identity Provider. We use the term *Other POD* in this spec to denote\nsome other WebID-OIDC compliant POD, acting as a Resource Server and Relying\nParty, that a user is trying to access using the WebID URI and Profile of their\nHome POD.\n\nWhen Alice tries to access a resource on Bob's POD, `alice.example` is her Home\nPOD, and `bob.example` plays the role of the Other POD.\n\n##### Public Client vs Confidential Client\nPublic - in-browser, mobile or desktop app, cannot be trusted with securely\nstoring secrets (private key material, secret client IDs, etc).\nConfidential - server-side app, can be trusted with secrets.\n\n##### Presenter\nA public client app that is trying to *present* a user's credentials from their\nhome POD to some other POD. For example, Bob is trying to access, via a client\napp, a shared file on Alice's `alice.example` POD, logging in using his own\n`bob.example` POD/provider. In this example, `bob.example` is a Provider, `alice.example` is\na Relying Party, and the client app (say, a browser-based HTML editor) is a\nPresenter.\n","funding_links":[],"categories":["Others","others"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsolid%2Fwebid-oidc-spec","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsolid%2Fwebid-oidc-spec","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsolid%2Fwebid-oidc-spec/lists"}