Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adjust the primer towards OIDC Federation #208

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
107 changes: 71 additions & 36 deletions primer/index.bs
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ Several actors are at play in our example Solid-OIDC authentication flows:
<dd>Decent Photos is a Solid compliant application and has a URI of its own,
which resolves to a Client ID Document. An RP's Client ID Document
contains information identifying them as a registered OAuth 2.0 client
application. Decent Photo's URI is `https://decentphotos.example/client_id`</dd>
application. Decent Photo's URI is `https://decentphotos.example`</dd>
<dt id="bob-pod">Bob's Storage</dt>
<dd>We will be trying to access photos stored in Bob's Storage. In our example, Bob
is a friend of Alice and has previously indicated via access control that Alice
Expand Down Expand Up @@ -235,6 +235,8 @@ Response Body:
}
```

Issue: OIDC Federation defines `client_registration_types_supported`, should it be addedhere, to `.well-known/oidc-federation` or both?
Copy link
Member

@acoburn acoburn Dec 5, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should definitely be added to OpenID Metadata resource (/.well-known/openid-configuration) for OPs that support clients from a federation.

If the OpenID Provider participates in a federation, the OP federation metadata would also contain this information (note the resource path: .well-known/openid-federation).

As I have been considering this change, I have been imagining the relying parties participating in an OIDC federation, but that it would entirely optional for an OpenID Provider to participate in a federation. Or are you thinking that this would be a requirement for Solid OIDC Providers as well?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! I'm going to add it to /.well-known/openid-configuration.

I think we should start with the minimum required, probably enough for RPs to act as entities in federation.

Copy link
Contributor

@woutermont woutermont Dec 6, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

At first I agreed, but now I'm fairly certain that the Federation spec only means to add that to the .well-known/openid-federation config, not change anything about the OIDC configuration. As long as we're not talking about OPs from a federation perspective, I thus think it should not be added anywhere.


The thing we care about here is the `authorization_endpoint` field. This will
be the url we use when we're ready to send an authorization request to the OP.

Expand Down Expand Up @@ -269,11 +271,13 @@ challenge anywhere.
Now that the web app is registered, we can finally make an auth request to authorize the web
application.

Issue: Change to match [OIDC Federation - Authentication Request](https://openid.net/specs/openid-connect-federation-1_0.html#name-authentication-request)

```http
GET https://secureauth.example/authorize?response_type=code&
redirect_uri=https%3A%2F%2Fdecentphotos.example%2Fcallback&
scope=openid%20webid%20offline_access&
client_id=https%3A%2F%2Fdecentphotos.example%client_id&
client_id=https%3A%2F%2Fdecentphotos.example&
code_challenge_method=S256&
code_challenge=HSi9dwlvRpNHCDm-L8GOdM16qcb0tLHPZqQSvaWXTI0
```
Expand All @@ -289,53 +293,84 @@ That URL might look a little complex, but it's essentially a request to
- `openid` is a scope that is needed to verify Alice's identity.
- `webid` is required by the Solid-OIDC specification to denote a WebID login.
- `offline_access`: Is required to get a refresh token.
- `client_id=https%3A%2F%2Fdecentphotos.example%2Fclient_id`: Usually the client id of a Solid
application is the app's URI (in our case `https://decentphotos.example/client_id`) as seen here.
- `client_id=https%3A%2F%2Fdecentphotos.example`: Usually the client id of a Solid
application is the app's URI (in our case `https://decentphotos.example`) as seen here.
- `code_challenge_method=S256`: Tells the OP that our code challenge was transformed using SHA-256.
- `code_challenge=HSi9dwlvRpNHCDm-L8GOdM16qcb0tLHPZqQSvaWXTI0`: The [=code challenge=] we generated before.

Note: If the app doesn't have a URI, you can either register an app using static registration
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we want to keep mentioning static registration?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

now I'm farily certain that the Federation spec only means to add that to the .well-known/openid-federation config

For an OP that is not part of a federation, how would a client know that the OP supports automatic registration? Unless you are suggesting that all such OPs must also participate in a federation? I had not been making that assumption.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure how that is related to (not) mentioning static registration? Did you mean to respons to the other conversation on client_registration_types_supported, @acoburn?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To answer to your question: I was assuming that a Solid-OIDC compliant OP would always adhere to the OpenID Federation spec, regardless of it being part of an actual federation or not; so every OP would always have a .well-known/openid-federation with the client_registration_types_supported list. Since that list has no defined meaning in OpenID Connect, however, I don't think it has any role in .well-known/oidc-configuration. But that's just how I initially interpreted it; might be wrong.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Aside: @woutermont this is in a different thread because the GH interface, for some inexplicable reason, will not allow me to comment on the relevant thread.

One perspective is that, if a Solid-OIDC OP is going to support the processing of RP Federation trust chains, it would make sense to also require the OP to participate in a Federation. After all, the OP is already implementing most of OIDC Federation, it could sure support the remaining APIs easily enough.

The other perspective is that the specific need on the part of Solid-OIDC is to be able to uniquely and securely identify RPs. Adding requirements to OPs above and beyond the needs of Solid only adds a burden to implementers.

I suspect that many Solid-OIDC OP implementations will also participate in a Federation, but I am wary of adding requirements that are not strictly necessary. It will be important to ensure that there is nothing in the text of the specification that prevents an IdP implementer from adding full OP support for federation.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I totally agree, @acoburn! We should not make it any more difficult for OPs than necessary.

I just don't see how my suggestion (not including client_registration_types_supported in .well-known/oidc-configuration) would do that. As I see it, the only thing we really require from OPs is that they support Automatic Registration, and declare that in their .well-known/openid-federation statement. There is no need to also declare it in .well-known/oidc-configuration, because it has no meaning for clients reading that configuration.

Unless I am mistaken, this entails no other requirements from the OP.

via some UI on the OP or use [dynamic registration](https://openid.net/specs/openid-connect-registration-1_0.html).

<h4 id="authorization-code-pkce-flow-step-7" class="no-num">7. Fetch RP Client ID Document</h4>
<h4 id="authorization-code-pkce-flow-step-7" class="no-num">7. Fetch RP Metadata</h4>

If an app URI is provided as the client id (see note above to see other options), we must
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd expect a break or header here to indicate that we're now switching from the app perspective to the OP perspective. Strange I haven't missed that before.

fetch that app URI to confirm its validity.
[Obtaining Federation Entity Configuration Information](https://openid.net/specs/openid-connect-federation-1_0.html#name-obtaining-federation-entity)

For the URI `https://decentphotos.example/client_id`, request the Client ID Document with:
For the URI `https://decentphotos.example`, request the Entity Statement from:
```http
GET https://decentphotos.example/webid
GET https://decentphotos.example/.well-known/openid-federation
```

Response:
```jsonld

```json
{
"@context": [ "https://www.w3.org/ns/solid/oidc-context.jsonld" ],

"client_id": "https://decentphtos.example/client_id",
"client_name": "DecentPhotos",
"redirect_uris": [ "https://decentphotos.example/callback" ],
"post_logout_redirect_uris": [ "https://decentphotos.example/logout" ],
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Post-logout redirect URI disappeared?

"client_uri": "https://decentphotos.example/",
"logo_uri": "https://decentphotos.example/logo.png",
"tos_uri": "https://decentphotos.example/tos.html",
"scope": "openid webid offline_access",
"grant_types": [ "refresh_token", "authorization_code" ],
"response_types": [ "code" ],
"default_max_age": 3600,
"require_auth_time": true
}
"iss": "https://decentphotos.example",
"sub": "https://decentphotos.example",
"iat": 1516239022,
"exp": 1516298022,
"metadata": {
"openid_relying_party": {
"application_type": "web",
"redirect_uris": [
"https://decentphotos.example/callback"
],
"organization_name": "DecentOrg",
"client_id": "https://decentphotos.example",
"client_name": "DecentPhotos",
"client_uri": "https://decentphotos.example",
"logo_uri": "https://decentphotos.example/logo.png",
"tos_uri": "https://decentphotos.example/tos.html",
"scope": "openid webid offline_access",
"grant_types": [
"authorization_code",
"refresh_token"
],
"response_types": [ "code" ],
"default_max_age": 3600,
"require_auth_time": true
"signed_jwks_uri": "https://openid.sunet.se/rp/jwks.jose",
"jwks_uri":"https://openid.sunet.se/rp/signed_jwks.json"
}
},
"jwks": {
"keys": [
{
"alg": "RS256",
"e": "AQAB",
"key_ops": [
"verify"
],
"kid": "key1",
"kty": "RSA",
"n": "pnXBOusEANuug6ewezb9J_...",
"use": "sig"
}
]
},
"authority_hints": [
"https://decent.example/federation"
]
}
```

Notice that the application Client ID Document contains a JSON-LD representation of an
[OIDC Client Registration](https://tools.ietf.org/html/rfc7591#section-2).
It also must use the specific <code>"@context": ["https://www.w3.org/ns/solid/oidc-context.jsonld"]</code>.
Issue: Details from [OIDC Federation - Processing the Authentication Request](https://openid.net/specs/openid-connect-federation-1_0.html#name-processing-the-authenticati)

<h4 id="authorization-code-pkce-flow-step-8" class="no-num">8. Validate redirect url with Client ID Document</h4>
<h4 id="authorization-code-pkce-flow-step-8" class="no-num">8. Validate redirect url with RP Metadata</h4>

Check to be sure that the `redirect_uri` value provided in the auth request
(`https://decentphotos.example/callback`) is listed in the `redirect_uris` array in the
Client ID Document. If it is not, the OP must reject the request. In our case, the
RP Metadata. If it is not, the OP must reject the request. In our case, the
`redirect_uri` is valid, so we may continue.

<h4 id="authorization-code-pkce-flow-step-9" class="no-num">9. Alice Logs In</h4>
Expand All @@ -354,7 +389,7 @@ id, the [=code challenge=], the user's webid, their desired response types, and
```json
{
"m-OrTPHdRsm8W_e9P0J2Bt": {
"client_id": "https://decentphotos.example/client_id",
"client_id": "https://decentphotos.example",
"code_challenge": "HSi9dwlvRpNHCDm-L8GOdM16qcb0tLHPZqQSvaWXTI0",
"webid": "https://alice.coolpod.example/profile/card#me",
"response_types": [ "code" ],
Expand Down Expand Up @@ -479,7 +514,7 @@ Body:
code_verifier=JXPOuToEB7&
code=m-OrTPHdRsm8W_e9P0J2Bt&
redirect_uri=https%3A%2F%2Fdecentphotos.example%2Fcallback&
client_id=https%3A%2F%2Fdecentphotos.example%2Fclient_id
client_id=https%3A%2F%2Fdecentphotos.example
```

- `headers.DPoP: "eyJhbGciOiJFUz..."`: The DPoP token we generated before. This will tell the
Expand All @@ -494,7 +529,7 @@ Body:
- `body.code=m-OrTPHdRsm8W_e9P0J2Bt`: The [=authorization code=] that we received from the OP upon redirect
- `body.redirect_uri`: The app's redirect url. In this case, this isn't needed because we're
doing an AJAX request.
- `body.client_id=https%3A%2F%2Fdecentphotos.example%client_id`: The app's client id.
- `body.client_id=https%3A%2F%2Fdecentphotos.example`: The app's client id.

Once this request is completed decentphotos can remove the code verifier from session storage.

Expand Down Expand Up @@ -559,8 +594,8 @@ Token Body:
```json
{
"sub": "https://alice.coolpod.example/profile/card#me",
"aud": [ "solid", "https://decentphotos.example/client_id"],
"azp": "https://decentphotos.example/client_id"
"aud": [ "solid", "https://decentphotos.example"],
"azp": "https://decentphotos.example"
"webid": "https://alice.coolpod.example/profile/card#me",
"iss": "https://secureauth.example",
"jti": "844a095c-9cdb-47e5-9510-1dba987c0a5f",
Expand All @@ -574,10 +609,10 @@ Token Body:

- `"sub": "https://alice.coolpod.example/profile/card#me"`: The subject claim. It must
be the same as the authenticated user's WebID.
- `"aud": "https://decentphotos.example/client_id"`: The token's audience. Because an
- `"aud": "https://decentphotos.example"`: The token's audience. Because an
id token is intended for the client and any Solid Authorization Server,
its audience is the client id and the string "solid".
- `"azp": "https://decentphotos.example/client_id"`: The token's authorized party. Because an
- `"azp": "https://decentphotos.example"`: The token's authorized party. Because an
id_token is intended to be used by the client, its authorized party is the client id.
- `"webid": "https://alice.coolpod.example/profile/card#me"`: The WebID of the user that
logged in
Expand Down