Solid Pod with JWT Verification

Do Solid Pod’s have the ability to generate a JWT and get if verified?

Ex.

  1. I login to my solid pod app (say on solidcommunity.net for example)
  2. I get a JWT from my login session
  3. I send this JWT to my backend app
  4. The backend app grabs the token, and uses this for verification (will have values on saved on backend):
{
  "Header":"",
  "Namespace":"",
  "Algo":"", 
  "VerificationKey":"",
  "JWKURL":"", 
  "Audience":[]
}
  1. The backend sends my JWT to the JWKURL for validation.
  2. My user is now verified on the backend.

Is something like this possible? This would basically allow my to replace Auth0 or Firebase Auth with Solid pods.

Thanks,

J

1 Like

There are two separate functions - a Pod Provider provides storage spaces and an Identity Provider (also called an IDP) provides OIDC identity services. Some servers provide both. The request for the token is not made to a Pod, but to the identity provider such as https://solidcommunity.net. Inrupt’s generate-oidc-token is a small app that gets a JWT from a variety of IDPs. Once you have the token, you can use it to make authenticated fetches to a Pod.

Does this work with one of the apps that is already hosted (solidcommunity, inrupt pod space, etc), or does this only work if I add this feature to a self hosting pod service?

I am not sure I understand how these POD providers can secure their logins at all, but surely there is a standard or they would not have their own hosting services?

How do I connect one of those Services to my own app securely if not with JWT?

Thanks,

J

All Identiy Providers that support Solid-OIDC compliant token flow (including solidcommunity.net, inrupt.net, inrupt.com) should follow the flow in the spec. The generate-oidc-token should work with any of them. It is for getting a JWT for use in an out-of-browser app. For browser apps, this is all taken care of by @inrupt/solid-client-authn.

Pods have ways to authorize users. Pod servers have ways to authenticate users with tokens supplied from Identity Providers.

Hi @jeffz,

Thanks for taking the time, as I am a newbie!

So lets say:

  • I have a user login to their POD, and that POD has a JWT in the user session (since this is standard web, I assume this is how it works)
  • I need to make sure if that user adds some information to my app (public information of course), it is that user, and not another user. What is the flow to verify this?

Example:

  1. I get the JWT from that user
  2. A user creates a public post in their POD and gives me access
  3. I store that post in my app’s database under that user’s webID
  4. How do I verify that webID is from that user?
    • obviously this is needed to prevent a user posting from someone else’s webID
    • or revoking access to the post, so that my app would delete it from my database

Would my backend (that posts to the database) verify this JWT (containing a claim with the webID) from the POD itself?

I am just blurry on the standard here to protect the user’s info.

Thanks,

J

I just wrote this so I may be leaving some things out, but here’s the general flow:

  1. Keisha registers with a Pod Provider and creates ResourceX in her new Pod.
  2. Alejandro registers with an Identity Provider and obtains a WebID.
  3. On her Pod, Keisha lists Alejandro’s WebID as having access to ResourceX.
  4. Alejandro uses an app to login to the Identity Provider.
  5. The Identity Provider sends the app a token.
  6. The app uses the token to visit ResourceX on Keisha’s Pod.
  7. Keisha’s Pod Provider uses the token to validate Alejandro’s WebID.
  8. The Pod Provider checks if Alejandro’s WebID is authorized for ResourceX.
  9. The Pod Provider gives the app (and Alejandro) access to resourceX.

[Edit : The Pod Provider also checks the origin of the app (as sent by the browser) and only provides access if Keisha has authorized BOTH Alejandro and the app he is using.]

[Edit Two : The Pod Provider and the Identity Provider may be the same server - they are for solidcommunity.net, inrupt.net, and inrupt.com. But they could also be separate. A Token from one of those is recognized by the others so you can login on solidcommunity.net and then access any private resources on inrupt.net that your solidcommunity.net WebID has authorization for.]

My example above is for a resource restricted to a specific set of WebIDs, in that case, the Pod Provider server does the checking to make sure that the WebID is accompanied by a token verifying it.

In the case you mentioned - a public folder anyone can write to. There is currently no mechanism AFAIK to verify who posted what.

So in your example Alejandro and Keisha are basically friends sharing information (or Keisha sharing her ResourceX to Alejandro) ?

So it seems I am thinking about this incorrectly. Does this sound correct:

  • I just need to tie in my app with the Identity Provider, and not the POD, and I can keep the same login across the board (Firebase Auth, oAuth — identity platforms with identity providers…)
  • The POD would just use the webID from that identity provider, so indirectly the login is shared
  • Once information is public in a POD, it is up to me to write my own protocols to allow the user to delete them from my end
  • There are no protocols for allowing my app access to data, the information is either public, or available to another user with a webID — my app with not have its own webID?

So in my case, I would just have the user login (login with google – oath i.e.). If a user creates a posts, they can save it to the POD if they want, but it is basically public information which doesn’t need a POD. Only safe information would be in the POD.

Does this seem right?

Thanks,

J

You’ve got a couple of things wrong (it’s complicated so that’s not unexpected).

Once information is public in a POD, it is up to me to write my own protocols to allow the user to delete them from my end

No the protocols exist. Every resource on a Pod has all or some of read, append,write, and control access as determined by you. On solidcommunity.net access is via .acl files in which you specify a resource or group of contained resources, an agent or agents or groups of agents or types of agents you want to access the resources and what access you grant them. All sorts of combinations are possible - any user, any authenticated user, any authenticated user in groupX, etc.

There are no protocols for allowing my app access to data, the information is either public, or available to another user with a webID — my app with not have its own webID?

No, there is a separate mechanism called trustedApps which allows the app to be trusted or not depending on its orign. To access a resource BOTH the app and the user need to be authorized.

So in my case, I would just have the user login (login with google – oath i.e.)

Maybe in the future. Currently you need to login to a Solid Identity Provider and Google isn’t (yet) one of those.

So it looks like trusted apps can just access data based on origin, is experimental, and may change. I am pretty sure this is not what I am looking for, unless SOLID does not tackle this kind of need.

Is this the only way for a POD to communicate with your app ?

I can only imagine very few circumstances where a user needs to see another user’s POD. Apps, not users, need to see a user’s POD in 99% of real world cases. I feel like I am missing something here.

Otherwise, it would be a nightmare having to read millions of pods around the world, sort them, provide different RBAC, cache them, just for a simple query about the latest posts. The only way I can see this makes sense, is to duplicate the “public” data in the app’s database. But how without a direct connection to the POD?

So I need an Identity Provider that supports SOLID, and pretty much only the few listed here support it for the moment, except self-hosting solutions, correct?

With that IDP, however, I can use a JWT across apps to verify that user is who they say they are?

Really, here is where my comprehension is lacking:

  1. How does an app, not a user, get data from a user’s POD (a post for example) — it seems to me it would only get the non-secure information at this point, which doesn’t have to be in the POD at all…

  2. Can I use a SOLID IDP for my authentication across the board (like any other IDP can with JWT). Otherwise I will have to have two different login systems, one for my app, one for the SOLID POD ?

I am not understanding the real-use-case scenario of SOLID, so obviously I am missing something.

Thanks!

J

So it looks like trusted apps can just access data based on origin, is experimental, and may change.

Correct, the Solid ecosystem is in flux. The plan is eventually to have apps have their own WebID with verifiable credentials. That day is not here yet.

I can only imagine very few circumstances where a user needs to see another user’s POD. Apps, not users, need to see a user’s POD in 99% of real world cases. I feel like I am missing something here.

In Solid, everything is user-based. The data belongs to a user and the user sets the access rights to the data. Apps that amass user’s data and store it in a centralized place is exactly what Solid is designed to avoid.

Otherwise, it would be a nightmare having to read millions of pods

It will take some doing, but if we stick with the current data-silo/apps-own-the-data model that is a real-life nightmare.

With that IDP, however, I can use a JWT across apps to verify that user is who they say they are?

Yes, across apps and across Pod Providers.

  1. How does an app, not a user, get data from a user’s POD (a post for example) — it seems to me it would only get the non-secure information at this point, which doesn’t have to be in the POD at all…

Correct, that is the whole idea of Solid - apps should not have access to private data unless they are run by an Agent who is authorized to access the data. An Agent, however could be an organization, a group of people, etc.

  1. Can I use a SOLID IDP for my authentication across the board (like any other IDP can with JWT).

Yes, a token from any IDP should give you access to any data the WebID for that token is authorized to access regardless of which Pod it is stored on.

@jdgamble555 these are great questions. @jeffz has already provided some really good explanations, and I’ll try to build on those.

One of the more significant differences between Solid apps and a more traditional web application is the separation between the user’s data and the app. If you think about a traditional web application, there is typically an internal database where that data is stored. Even if there is an API for accessing that data, the API tends to be application-specific. With Solid, that model is very different: the app and the data are separate. Basically, your Pod is the database. This means that different apps can use the same data, and because the Solid protocol defines an API, all those apps can read and write this data regardless of where it is stored (provided, of course that the user has appropriate access).

To your specific questions about JWT and identity – @jeffz has already answered much of this, but I’ll try to rephrase some of the answers. This can be a bit complicated, so maybe phrasing it differently will help. In Solid, there are a few different conceptual entities: WebID (Identity), Pod (Storage), Identity Provider (Asserts Identity) and Apps (User-facing Features). It is possible to combine these in different ways or to have them all completely separate. For example, a WebID could be stored in a user’s Pod, but that isn’t a requirement. Also, the Identity Provider may run on the same domain as the Pod, but again, that isn’t a requirement.

In terms of login / identity / JWT, it is important to clarify a few things. First, there is a two-way trust relationship between a User’s WebID and an Identity Provider. That is, the Identity Provider will generate access tokens in the form of JWT containing an identity claim about the agent in possession of that token. Specifically: the JWT will have a webid claim along with an Issuer (iss) claim. When a Pod (Storage / Resource Server) validates that token, it will dereference the WebID URL and look for a trust relationshp with the issuing Identity Provider. That way I can’t just craft an otherwise valid JWT that claims to be someone else. That two-way trust is a major building-block for Solid’s security model. In passing, I will add that this all builds on OpenID Connect, so all the security mechanisms from OpenID come into play: authorization code flow, “Proof Key for Code Exchange”. Solid also uses something called Demonstration of Proof of Possession to protect against rogue resource servers from replaying access tokens.

Put simply, an App will retrieve an access token (JWT) from an Identity Provider, not from a Pod (though the two may be co-located). That access token will assert a globally unambiguous identity for the user: a WebID. The App will use that access token to read and write data to one or more Pod servers. From the access token, a Pod server will always know the identity that an agent is claiming. Also, the data that your app writes may or may not be public: your app may store data in an area that may be shared, but that isn’t required.

I hope that helps

3 Likes

@acoburn Thanks for the answer.

But it is always stored in the POD, correct?

In order to search, filter, cache, scale, etc, some of that data needs to be taken out of the POD to be usable by an app. From my understanding above, this is fine, because it is public data (posts, tweets, public username, etc… and not… likes, – ad AI – real demographics, etc.) That information would not need to be stored outside the POD anyway, as the only people looking to cache and search through it would be Big Tech, hence, new protocol. Am I understanding it correcly?

Right. So, I just want to make sure I can use this same Identity Provider for my app that the SOLID uses. JWT seems to be standard here. Otherwise I need two login systems.

J

I think perhaps two things you are missing.

Solid data is smart data, it has internal semantics and semantic links to other data. So a lot of the burden is taken off the app - if the app can understand RDF, it can let the data tell it what to do.

Suppose I download and authorize an app run by the Fire Spinners forum. That app has my permission to get stuff that I want other members of the Forum to see but not anyone else. Other members of the forum do the same. The app now can share private data between us without storing anything.

@jeffz - I don’t think that would not work in the real world, which is where I am having trouble understanding.

If Fire Spinners has a million plus users who are all viewing the front page with the latest posts that users are sharing, each POD from each form would incur 1 million reads. It would be incredibly slow, lack caching, and you would have to search (RDF) through millions of user’s pods to get the latest posts, etc. Even if the search was feasible (semantic links), one million users would be a burden on the POD (which from my understanding no one has yet used the protocol to store the data in any other format besides text).

Even 100,000 users would have loading problems. Allowing more than a few groups of people at a time access to a POD would certainly cause problems. Should each user have to pay for the bandwidth of one app reading the POD consistently?

The only other way around that without breaking the SOLID protocol (from my understanding), is to have a middle scalable database to store the users public data. Posts would be public, chats would not. However, even a private chat room allowing one group of people with a million users would have problems reading POD to POD.

So getting around all of that, I believe that real apps with PODS basically cannot scale without being centralized… which would be against SOLID protocol to have the private data that way. So, we only share the public data, not private, in a centralized place.

So to get out of theory and into practice mode, here is what I am thinking:

  • My app has a login page, which uses a SOLID Identity Provider to login to any POD
  • After login, the JWT keeps me logged in across my app and the POD
  • My app has a create-post (or whatever information) which creates a POST, and saves it to the user’s POD. My app scans the POD for that public post, and saves it to a centralized database (it is public afterall)
  • Any direct chat features would use POD to POD
  • The public data would only be my username… which links to the private data in my POD — my SSN, address, email, full name, etc…
  • I write my own way for the user to delete their info out of my app (nothing to do with SOLID, but just good practice)

I believe real apps need to scale, and cannot without having that data centralized. However, the private data does not need to be, which to me is why I would want to user SOLID.

Maybe I have this all wrong, but this is the only thing that makes sense to me.

J

There are 2 ways I can think of to construct the front page:

  1. Either start with the people you know (foaf:knows) and get their latest posts (or latest upvotes), then go fetch the people they know, and so on. This means that the page takes an infinite amount of time to build itself, but the first results to appear are fast and relevant.
  2. The forum indexes a list of known interesting posts and caches that list (see how Google caches short site descriptions when you do a search).

Obviously, a successful forum would be a combination of both.

They don’t have to be on the same POD.

If a million people visit my site once, every pod with the latest posts gets a million hits. My pod would get a million hits.

Wouldn’t that be what I said earlier, and just my external scalable database being used as a cache? Of course that would have to be public data…

But what about posts from people not foaf? I need to get out of my own bubble and read what is trending for everyone…

J

Nobody has yet written Solid apps that have had to scale to that number of users, so while app-specific backends that cache Pod data have been considered, it is still a mostly theoretical exercise. However, it certainly is something that should be possible.

The way it could work is that, when connecting to their Pods, users authorise your backend server to act on their behalf - that is, your backend server will communicate with the Solid Identity Provider to obtain an Access Token (and a Refresh Token, to obtain a new Access Token when it expires), with which it will be able to access private data on the user’s Pod. Your app can then relay all requests through your app’s back-end, which can cache as necessary - even private data. I believe this is how @jaxoncreed’s Liqid Chat works (source code). Server-side authentication is also something you could use the Node version of Inrupt’s auth library for if you’re using Node.js - and if not, its source code might be helpful.

Alternatively you could indeed just cache public data only. However, if that’s the case, I’m not sure why your backend would even need a token? After all, if the data is public anyway, your app can just send your backend the URL(s) of the public data it would want to access, and your backend can return that data either directly from cache, or first fetching it if it’s not fresh in the cache?

If you do want your backend to only accept such requests by users who are logged in, it could do the same thing a Storage / Resource Server does: validate the user’s token with their Identity Provider. That said, it is trivial (not really, but there’s nothing blocking people) to set up your own Identity Provider (it’s decentralised, after all), so there’s nothing much in particular that can be gained from this, I think.

Even if there were 10 PODS that were scalable, if one user put their POD on their home computer with a slow internet connection, it seems to me the whole app would be slow…

Maybe if your app was a POD itself that used a scalable database instead of a text file (keeping with SOLID protocols)? The app itself could be a POD, not just for users?

Kind of what I was thinking…

Darcy allows you to view your friends posts, but before you can be-friend anyone, you need to follow / unfollow feeds, which I guess would be public data.

Just kind of wondering if someone built like a basic Twitter-like app (simplest social media app I know) to convey how this would work… the concepts are interesting.

J

Just to add that the fediverse already tackles this kind of thing in a decentralized context, and that part of the solution is the use of notifications rather than accessing pods at read-time (e.g. see linked data notifications). Basically the app accesses a user’s local mirror of the content aggregated from across the network. Crawling pods to find new posts is not the only solution.

The solid spec just addresses a small part of the decentralization puzzle, primarily around authentication, authorisation and a bit on the interoperability side. There’s lots of other pieces to draw on for the rest of that puzzle.

1 Like