1. Introduction
The introduction for the Aggregator specification will be expanded in future revisions.
2. Definitions
add a link to other specs used: WebID, OIDC, UMA
-
IDP Server (IDPS): An Identity Provider server that supports OIDC and issues OIDC tokens.
NOTE: that this is different from the Authorization Server (AS) that issues UMA RPT tokens. The IDP Servers are used to provide identity to users. The Authorization Servers checks this identity and issues RPT tokens for resource servers.
-
Authorization Server (AS): An OAuth2 Authorization Server that supports UMA and issues RPT tokens.
-
Resource Server (RS): An OAuth2 Resource Server that protects resources and accepts RPT tokens issued from a Authorization Server.
-
Aggregator Server: A server that hosts multiple Aggregators.
-
Aggregator: A service that manages multiple Aggregator Services and allows user to create and use them.
-
Aggregator Service: A service that aggregates data from multiple Resource Servers on behalf of a user.
-
Client: An application that interacts with the Aggregator Service.
-
ClientID: A JSON-LD document that describes a Client. It is dereferenceable via a URL.
-
User: A person who owns resources on Resource Servers and uses the Client and Aggregator.
-
OIDC token
-
Authorization server
-
Resource server
3. Public Metadata
-
Well-known endpoint
-
Creation endpoint
-
client.jsonendpoint that exposes the client identifier used for authorization
4. Registration Endpoint
This section describes how aggregators are managed on the Aggregator Server level. The authorization for these endpoints is defined by the implementation and up to the Aggregator provider to decide. The user requires authenticated requests to manage their aggregator accounts on wich the Aggregator provider can base their authorization decisions. The tokens used in these requests (IPD_client_token) prove the identity of the user and the client (ClientID) used to access the aggregator.4.1. Aggregator Creation
This section describes how clients can create an Aggregator. There exists different flows to create an aggregator depending on the registration type.TODO where to add versioning info?
TODO where to use DPOP tokens?
TODO what about HTTP error handling?
4.1.1. provision Flow
The provision flow allows clients to create an Aggregator with its own identity.
This lets resource owners target access-control policies at the aggregator’s dedicated WebID instead of having the aggregator impersonate another user’s WebID.
1. Client starts flow with Aggregator Server
The client calls the registration endpoint authenticated with its IPD_client_token.
POST /registration HTTP / 1.1 Authorization : Bearer <IPD_client_token> Content-Type : application/json { "registration_type" : "provision" , }
2. Aggregator Server provisions a WebID and registers it at the IDP
The Aggregator Server creates a WebID document and registers a new account with an IDP for that WebID.
Using the credentials of this new account the Aggregator Server CAN perform a client credentials flow to obtain the IDP_aggregator_token (and accompanying refresh token) to authorize the aggregator acting under its own WebID.
TODO should this WebID specify that it is an aggregator/agent?
3. Aggregator Server creates an aggregator
Using the obtained tokens, the Aggregator Server creates an aggregator linked to the user, and returns the aggregator metadata and newly created WebID. The aggregator CAN NOT give these tokens or client credentials to the client.
4.1.2. authorization_code Flow
The authorization_code flow allows clients to create an aggregator that acts on behalf of the end-user, but with a token that is scoped specifically for the aggregator.
1. Client starts flow with Aggregator Server
The client begins by asking the Aggregator to bootstrap an authorization_code registration and indicate which authorization server should be used. The Aggregator responds with the public parameters required for the OIDC authorization request.
POST /registration HTTP / 1.1 Authorization : Bearer <IPD_client_token> Content-Type : application/json { "registration_type" : "authorization_code" , "authorization_server" : "https://as.example" }
1.1 Aggregator dereferences the WebID to discover the IDP
Using the UMA authorization context, the Aggregator dereferences the user’s WebID profile document to locate the Solid/OIDC issuer metadata and determine which IDP endpoints must be used for the next steps.
1.2 Aggregator responds with public parameters
After finishing WebID discovery and storing the PKCE verifier/state, the Aggregator returns the public parameters required for the IDP authorization request.
HTTP / 1.1 201 Created Content-Type : application/json { "client_id" : "https://aggregator.example/client.jsonld" , "code_challenge" : "1uLSZp2..." , "code_challenge_method" : "S256" , "state" : "1eb7c8f5..." }
The Aggregator generates the PKCE verifier/challenge pair plus a random state, persists them together with the pending registration, and returns only the public portions (client_id, code_challenge, state) to the client application.
The authorization_server value identifies the UMA Authorization Server (AS) that governs resource policies; once the Aggregator evaluates the user’s authorization token it can dereference its WebID and determine which Identity Provider (IDP) must be used for the subsequent OIDC exchange.
TODO How does the aggregator register with the AS?
2. Client sends the end-user through the IDP authorization endpoint
Using the information supplied by the Aggregator, the client constructs an authorization request against the Identity Provider.
The redirect_uri is under control of the client application and MUST already be registered in the JSON-LD client metadata document hosted at the dereferenceable client_id.
GET https://idp.example/authorize?
response_type=code&
client_id=https%3A%2F%2Faggregator.example%2Fclient.jsonld&
redirect_uri=https%3A%2F%2Fapp.example%2Fcallback&
scope=openid%20webid%20offline_access&
code_challenge=1uLSZp2...&
code_challenge_method=S256&
state=1eb7c8f5...
3. User authenticates and consents at the IDP
The IDP performs its usual login and consent screens, after which it issues an authorization_code tied to the Aggregator’s confidential client.
4. IDP redirects the user agent back to the client’s redirect_uri
HTTP / 1.1 302 Found Location : https://app.example/callback?code=SplxlOBeZQQYbYS6WxSbIA&state=1eb7c8f5...
5. Client posts the authorization code back to the Aggregator
The client sends the code, redirect URI, and echoed state to the registration endpoint so the Aggregator can finish the flow.
POST /registration HTTP / 1.1 Authorization : Bearer <IPD_client_token> Content-Type : application/json { "registration_type" : "authorization_code" , "code" : "SplxlOBeZQQYbYS6WxSbIA" , "redirect_uri" : "https://app.example/callback" , "state" : "1eb7c8f5..." }
5.1 Aggregator dereferences the client metadata
The Aggregator dereferences the client_id JSON-LD document to confirm the registered redirect URIs, contact metadata, and other security requirements, then verifies that the supplied redirect_uri belongs to that set and that the returned state matches the stored nonce.
5.2 Aggregator redeems the authorization code at the IDP token endpoint
POST /token HTTP / 1.1 Host : idp.example Content-Type : application/x-www-form-urlencoded Authorization : Basic <aggregator-client-auth> grant_type = authorization_code & code = SplxlOBeZQQYbYS6WxSbIA & redirect_uri = https%3A%2F%2Fapp.example%2Fcallback & client_id = https%3A%2F%2Faggregator.example%2Fclient.jsonld & code_verifier = Hjs8...stored...
The IDP verifies the authorization_code, ensures the redirect_uri matches the original authorization request, and recomputes the PKCE challenge from the supplied code_verifier. If everything matches, it returns:
HTTP / 1.1 200 OK Content-Type : application/json { "access_token" : "<IDP_aggregator_token>" , "refresh_token" : "<refresh_token>" , "token_type" : "Bearer" , "expires_in" : 3600 }
5.3 Aggregator finalizes the account and responds
Using the issued tokens, the Aggregator creates the aggregator account linked to the user and returns the aggregator account details to the client.
HTTP / 1.1 201 Created Content-Type : application/json { "aggregator_id" : "agg-7890" , "authorization_server" : "https://as.example" , "webid" : "https://aggregator.example/webids/agg-7890#id" , "token_expires_in" : 3600 }
4.1.3. client_credentials Flow
The client_credentials flow allows clients to create an aggregator by using the OAuth2 Client Credentials Flow to obtain an OIDC token from an Identity Provider (IDP) server.
NOTE: This flow gives the aggregator complete access to the user’s resources and policies without user consent. This flow should only be used in trusted environments, or when a user creates an account for the aggregator.
1. Client starts flow with Aggregator Server
The client explicitly asks the Aggregator to act with full credentials for the provided WebID, indicating which UMA Authorization Server manages the protected resources. Because this flow hands the Aggregator long-lived credentials, it should only be used when the user intentionally provisions the Aggregator as a trusted service account.
POST /registration HTTP / 1.1 Authorization : Bearer <IPD_client_token> Content-Type : application/json { "registration_type" : "client_credentials" , "authorization_server" : "https://as.example" , "webid" : "https://user.example/webid#me" , "username" : "alice@example.org" , "password" : "s3cr3t-password" }
2. Aggregator Server performs credential bootstrap with the IDP
The Aggregator uses the supplied username/password (plus the WebID context) to authenticate against the Identity Provider’s management or token endpoint, registering (or reusing) a confidential client that represents the Aggregator’s service account for that user. It then runs an OAuth 2.0 client_credentials grant using the obtained client_id/client_secret to mint an IDP_aggregator_token scoped to the user’s WebID.
POST /token HTTP / 1.1 Host : idp.example Content-Type : application/x-www-form-urlencoded Authorization : Basic <aggregator-client-auth> grant_type = client_credentials & webid = https%3A%2F%2Fuser.example%2Fwebid%23me & scope = openid%20webid%20offline_access
The IDP issues access and refresh tokens that grant the Aggregator the same capabilities as the user’s own credentials.
HTTP / 1.1 200 OK Content-Type : application/json { "access_token" : "<IDP_aggregator_token>" , "refresh_token" : "<refresh_token>" , "token_type" : "Bearer" , "expires_in" : 7200 }
3. Aggregator Server creates (or updates) the aggregator account
Armed with the IDP_aggregator_token, the Aggregator persists the account for the specified WebID, associates it with the requesting user, and returns the aggregator account metadata (aggregator identifier, token expiry, UMA AS linkage, etc.) to the client.
4.1.4. device_code Flow
NOTE: TODO This flow is not yet specified.
4.2. Aggregator Login
The login flow allows users to update the tokens of their existing aggregator. This flow can be used to refresh the tokens in case they have expired. The flow is the same as with creating an aggregator but a aggregator_id parameter is provided in step 1. The exact steps depend on the registration_type used when creating the aggregator. For example for theauthorization_code flow:
POST /registration HTTP / 1.1 Authorization : Bearer <IPD_client_token> Content-Type : application/json {"registration_type" : "authorization_code" , "aggregator_id" : "agg-7890" }
4.3. Aggregator Deletion
The delete flow allows users to delete their existing aggregator. This flow is done by doing a DELETE request to the registration endpoint with the aggregator_id parameter.DELETE /registration HTTP / 1.1 Authorization : Bearer <IPD_client_token> Content-Type : application/json {"aggregator_id" : "agg-7890" }
5. Authentication and Authorization
The Aggregator relies on the Authorization for Data Spaces (A4DS) specification to authenticate clients and authorize access to resources. The Aggregator Service authenticates the Client using OIDC and obtains access tokens for upstream Resource Servers.
5.1. Client Flow
The Aggregator Service authenticates the Client with OIDC to obtain an access token for a Resource Server.
The Aggregator Service relies on an OIDC access token linked to the Aggregator’s client identifier.
The Aggregator SHOULD request the additional scope urn:knows:uma:scopes:derivation-creation from the Authorization Server of a Resource Server to enable the Aggregator functionality.
The Authorization Server MUST return a derivation_resource_id together with the access token.
The Aggregator MAY delete the derivation_resource_id when it is no longer needed.
The Aggregator Service MUST update the resource registration at its Authorization Server to signal that it used this resource identifier to create derived resources.
{ "resource_scopes" : [ ...], "resource_relations" : { "prov:wasDerivedFrom" : { "issuer" : "https://as.example.org" , "derivation_resource_id" : "handle-id-1" } } }
The Authorization Server MUST invalidate previous access tokens (for example by marking them inactive) if they are linked to a derived resource whose identifier has been consumed.
TODO: clarify whether polling for a new derivation_resource_id is necessary, or whether the Aggregator can request the Authorization Server for a normal scope referencing the identifier or supply the identifier as a hint when requesting with a ticket.
5.2. Resource Server Flow
When a Client requests access to a derived resource from the Aggregator Service, a normal UMA flow follows.
During ticket creation, the Aggregator validates that the derivation_resource_id used to create the derived resource is still valid.
If it is invalid, the Aggregator MUST recreate the Aggregator Service.
The Aggregator Authorization Server MAY respond with a need_info error requesting access tokens for upstream resources.
In that case, the Authorization Server MUST add the issuer, derivation_resource_id, and resource_scopes entries to the required_claims array.
The issuer identifies the upstream Authorization Server.
The derivation_resource_id contains the identifier (or identifiers) provided when the Aggregator Service requested an upstream access token.
The resource_scopes list enumerates the scopes required to access the upstream resource and MUST include a derivation scope.
{ "error" : "need_info" , "ticket" : "tkt-A2" , "required_claims" : [ { "claim_token_format" : "urn:ietf:params:oauth:token-type:access_token" , "details" : { "issuer" : "https://a.example.org" , "derivation_resource_id" : "handle-id-1" , "resource_scopes" : [ "urn:knows:uma:scopes:derivation-read" ] } } ] }
The Client SHOULD then request access tokens from the Authorization Server of the upstream Resource Server with the required scopes, including the derivation scope.
{ "grant_type" : "urn:ietf:params:oauth:grant-type:uma-ticket" , "permissions" : [ { "resource_id" : "handle-id-1" , "scopes" : [ "urn:knows:uma:scopes:derivation-read" ] } ], "claim_token" : "OIDC_token" , "claim_token_format" : "http://openid.net/specs/openid-connect-core-1_0.html#IDToken" }
Finally, the Client retries the request to the Aggregator Service with the access tokens it received from the upstream Resource Servers.
{ "grant_type" : "urn:ietf:params:oauth:grant-type:uma-ticket" , "ticket" : "tkt-A2" , "claim_tokens" : [ { "claim_token" : "OIDC_token" , "claim_token_format" : "http://openid.net/specs/openid-connect-core-1_0.html#IDToken" }, { "claim_token_format" : "urn:ietf:params:oauth:token-type:access_token" , "claim_token" : "as-at-2" } ] }
The Aggregator Authorization Server MUST verify the provided access tokens with the upstream Authorization Servers to confirm that the Client is authorized to access the upstream resources.