API for creating solid pods

Hi,

I am currently working on a project where i have to create solid pods for students and give them the pods access with temporary passwords. Is there any API available to talk to the solid node server to create solid PODs programatically? Or i have to modify the source code of the node server to achieve this? (P.S. We have our own solid server).

Thanks.

Did you ever get an answer for this? I have a similar use-case.

It is possible to do this with CSS and NSS, though I donā€™t think anyone has written a specific guide; itā€™s mostly about putting the right data & files in place, as both servers are filesystem based (compared to ESS which is postgresql/mongodb + s3-like storage, iirc)

OK, so I have grabbed a clone of GitHub - nodeSolidServer/node-solid-server: Solid server on top of the file-system in NodeJS and am running a local bin/solid-test instance to check what data is saved where for multiple users and it looks like I just need to add a suitable entry in the
ā€˜.db/oidc/users/usersā€™ folder for each user, and add a folder in the /data directory for each user replicating the structure the ones already there.

Does that sound like it covers everything?

Seed pods on CSS Seeding Pods - Community Solid Server

Well I have not seen it done before.
Normally to create a pod, you need to create :

  • entry in .db for user and email with encoded password
  • pod structure with email in root .acl

CSS as a working api to do that

Thanks! That Community Solid Server looks like it will do the trick.

Thereā€™s also bashlib which makes it easy to setup pods on CSS

What is the working API on CSS to do this? I cannot seem to find it. And also, I want to do it without having to login, thanks

Hi SolarDrift,

The current (v7) Authentication API for CSS is documented here: JSON API - Community Solid Server

I havenā€™t used this version yet, but looking at the documentation and trying it out a bit, here is how I created an account and setup a login via email+password. I guess you can use a similar approach to setup pods and authentication via OIDC or client credentials.

// get available endpoints
res = await fetch('http://localhost:3000/.account/')
data = await res.json()
controls = data.controls

// create an account (requires no parameters)
res = await fetch(controls.account.create, { method: 'POST' }) 
data = await res.json()
authorizationValue = data.authorization

// get available endpoints, but now for the fresh account (should also work via the cookie, authorization header is probably not necessary)
res = await fetch('http://localhost:3000/.account/', { headers: { authorization: `CSS-Account-Token ${authorizationValue}` } })
data = await res.json()
controls = data.controls

// get necessary fields for the POST request
res = await fetch(controls.password.create, { headers: { authorization: `CSS-Account-Token ${authorizationValue}` } })
data = await res.json()
console.log(data.fields) // tells us we need email+password parameters for the POST request

// setup a login via email+password for the current account
res = await fetch(controls.password.create, {
  headers: {
    authorization: `CSS-Account-Token ${authorizationValue}`,
    'content-type': 'application/json'
  },
  method: 'POST',
  body: JSON.stringify({
    email: 'test@example.org',
    password: 'secret-12345',
  }),
})
data = await res.json()


// now we can login with email+password
res = await fetch(controls.password.login, {
  headers: {
    'content-type': 'application/json'
  },
  method: 'POST',
  body: JSON.stringify({
    email: 'test@example.org',
    password: 'secret-12345',
  }),
})
data = await res.json()
authorizationValue = data.authorization

// get available endpoints for current account
res = await fetch('http://localhost:3000/.account/', { headers: { authorization: `CSS-Account-Token ${authorizationValue}` } })
data = await res.json()
controls = data.controls

I hope this helps you :slight_smile:

4 Likes

You have just made my day! Thank you so much! :slight_smile:

I just put this in my nodejs express API and it works as expected, creates the account, but at the available controls last line:

controls = data.controls

When console, there is just the basic account endpoints exposed.

How do I create a pod with a new webID and name? Like what endpoint to use?

It created the account here:
https://secure.agefix.space/.account/account/11e78a20-3f7f-4a68-8f71-7650dbae1e01/

API Docs shows it here:
https://communitysolidserver.github.io/CommunitySolidServer/7.x/usage/account/json-api/#controlsaccountpod

POST request but no idea how to construct it:

res = await fetch(controls.account.pod, {
headers: {
authorization: CSS-Account-Token ${authorizationValue},
ā€˜content-typeā€™: ā€˜application/jsonā€™
},
method: ā€˜POSTā€™,
body: JSON.stringify({
name: uniqueID // POD NAME SET TO USERS UNIQUE ID FOR EASY REFERENCE
}),
})
data = await res.json()
console.log('Pod created: ā€™ + JSON.stringify(data));

I just get error: TypeError: Invalid URL, guessing it does not recognise the ā€œcontrols.account.podā€

Yet when I login on UI instead, it allows me to create a new pod which assigns a webID, so the configuration must be correct, just not exposed to the API?

Thanks
Paul

1 Like

Hi Paul,

Iā€™ve updated my code above slighly (replaced the second controls.password.create with controls.password.login and added the authorization header for the last api call).

When you execute this with your authorizationValue and origin (secure.agefix.space instead of localhost):

// get available endpoints for current account
res = await fetch('http://localhost:3000/.account/', { headers: { authorization: `CSS-Account-Token ${authorizationValue}` } })
data = await res.json()
controls = data.controls
console.log(controls.account.pod)

What does it log for the pod API url? In my case it is http://localhost:3000/.account/account/720537bf-be2b-4cce-a0b6-844c058c7754/pod/

Thatā€™s good to hear. The UI uses the same API (you can find the source here). You could also inspect the network requests in the browser dev tools to see which requests it makes to create the pod. Note that the UI seems to rely on cookies for authentication, in nodejs you should add the authorization header to authenticate.

2 Likes

Ok thank you I will give it go.

response = await fetch(ā€˜https://secure.agefix.space/.account/ā€™, {
headers: { authorization: CSS-Account-Token ${authorizationValue} }
})
data = await response.json()
controls = data.controls
console.log('controls.account.pod: ā€™ + controls.account.pod);

controls.account.pod: undefined

OK, so I now do not get the InvalidURL response anymore, after changing it to the controls.password.login, then controls.account.pod:

response = await fetch(controls.account.pod, {
headers: {
authorization: CSS-Account-Token ${authorizationValue},
ā€˜content-typeā€™: ā€˜application/jsonā€™
},
method: ā€˜POSTā€™,
body: JSON.stringify({
name: uniqueID // POD NAME SET TO USERS UNIQUE ID FOR EASY REFERENCE
}),
})
data = await response.json()
console.log('Pod response: ā€™ + JSON.stringify(data));

I intead get response: {ā€œnameā€:ā€œUnauthorizedHttpErrorā€,ā€œmessageā€:ā€œā€,ā€œstatusCodeā€:401,ā€œerrorCodeā€:ā€œH401ā€,ā€œdetailsā€:{}}

1 Like

This sounds like your authorizationValue is not properly set.

Hereā€™s the complete script that created https://secure.agefix.space/testomate/

You can save it as someScript.js locally and execute with node someScript.js

// baseUrl = 'http://localhost:3000'
baseUrl = 'https://secure.agefix.space'
indexUrl = baseUrl + '/.account/'

async function main() {
// get available endpoints
res = await fetch(indexUrl)
data = await res.json()
controls = data.controls

// create an account (requires no parameters)
res = await fetch(controls.account.create, { method: 'POST' }) 
data = await res.json()
authorizationValue = data.authorization

// get available endpoints, but now for the fresh account (should also work via the cookie, authorization header is probably not necessary)
res = await fetch(indexUrl, { headers: { authorization: `CSS-Account-Token ${authorizationValue}` } })
data = await res.json()
controls = data.controls

// setup a login via email+password for the current account
res = await fetch(controls.password.create, {
  headers: {
    authorization: `CSS-Account-Token ${authorizationValue}`,
    'content-type': 'application/json'
  },
  method: 'POST',
  body: JSON.stringify({
    email: 'test@example.org',
    password: 'secret-12345',
  }),
})
data = await res.json()


// now we can login with email+password
res = await fetch(controls.password.login, {
  headers: {
    'content-type': 'application/json'
  },
  method: 'POST',
  body: JSON.stringify({
    email: 'test@example.org',
    password: 'secret-12345',
  }),
})
data = await res.json()
authorizationValue = data.authorization

// get available endpoints for current account
res = await fetch(indexUrl, { headers: { authorization: `CSS-Account-Token ${authorizationValue}` } })
data = await res.json()
controls = data.controls
console.log(controls.account.pod)


// setup a pod
res = await fetch(controls.account.pod, {
  headers: {
    authorization: `CSS-Account-Token ${authorizationValue}`,
    'content-type': 'application/json'
  },
  method: 'POST',
  body: JSON.stringify({
    name: 'testomate',
  }),
})
data = await res.json()

console.log(`Created pod: ${JSON.stringify(data, undefined, 2)}`)
}

main()
1 Like

Canā€™t thank you enough! Really appreciate your help.

Now I can move onto the fun bits with patient data ownership and medical record history

If I could buy you a beer I would :slightly_smiling_face:

Cheers

2 Likes

Hi,

Can this same approach be used to write and read RDF data to the pod and also physical files like documents? I am struggling to integrate. All examples I have found are doing it from the client not the server like above and using ESS not CSS. I want them to be private too, not publicly accessible.

Would using solid-client library work?

https://docs.inrupt.com/developer-tools/javascript/client-libraries/tutorial/read-write-files/#write-a-file

Thanks
Paul

Iā€™m assuming that the question here is ā€œnow can a script authenticate itself on the CSS and then read/write documents to a Podā€.

One option is to use Client credentials - Community Solid Server to create an authenticated fetch function so that your script authenticates itself as the WebID owning the Pod that you want to read/write to and then use that fetch function in the code sample from Read/Write Files (Non-RDF Resources) ā€” Inrupt JavaScript Client Libraries.

2 Likes

You may look at

1 Like