Solid-client-authn-node / solid-client authorized requests

Hi, I’m trying out the solid-client-authn-node application for a Node.js backend service.

I’ve followed all the Inrupt tutorials but I got stuck with the authorized requests.

https://docs.inrupt.com/developer-tools/javascript/client-libraries/using-libraries/

As mentioned in the tutorials, while performing authorized requests we should always pass the fetch function from the authorized Session to the solid-client methods.

So in my codebase I wanted to do that, but I keep getting errors while passing the fetch function.

const express = require("express");
const cookieSession = require("cookie-session");

const {
  getSessionFromStorage,
  getSessionIdFromStorageAll,
  Session
} = require("@inrupt/solid-client-authn-node");

const {
  access,
  getSolidDataset
} = require("@inrupt/solid-client")

const app = express();
const port = 3000;

app.use(express.json());
app.use(express.urlencoded());

// The following snippet ensures that the server identifies each user's session
// with a cookie using an express-specific mechanism
app.use(
  cookieSession({
    name: "session",
    // These keys are required by cookie-session to sign the cookies.
    keys: [
      "Required, but value not relevant for this demo - key1",
      "Required, but value not relevant for this demo - key2",
    ],
    maxAge: 24 * 60 * 60 * 1000, // 24 hours
  })
);

// Login endpoint: returns the link to the OIDC provider
app.get('/login', async (req, res) => {
  const session = new Session();
  req.session.sessionId = session.info.sessionId;

  //redirect url and oidc issuer fetched from the request body
  const redirectUrl = "http://localhost:3000/handleRedirect"
  const oidcIssuer = "https://solidcommunity.net"

  //return the link to the OIDC provider
  const returnSolidIdentityProviderLoginUrl = (url) => {
    res.send(url)
  }

  await session.login({
    redirectUrl: redirectUrl,
    oidcIssuer: oidcIssuer,
    clientName: "Covid Safe App Cronos",
    handleRedirect: returnSolidIdentityProviderLoginUrl
  })
});

// OIDC provider redirects back to this endpoint
app.get("/handleRedirect", async (req, res) => {
  let code = req.url.split('?')[1]

  const session = await getSessionFromStorage(req.session.sessionId);
  await session.handleIncomingRedirect(`http://localhost:${port}/handleRedirect?${code}`);

  if (session.info.isLoggedIn) {
    return res.send(`<p>Logged in with the WebID ${session.info.webId}.</p>`)
  }
})

app.get("/fetch", async (req, res) => {
  const session = await getSessionFromStorage(req.session.sessionId);
  const resource = encodeURI("https://warddriesen.solidcommunity.net/private/private_resource")

  if (!session || !session.info.isLoggedIn) {
    return res.status(401)
  }

  if (!resource) {
    return res.status(404).json({ error: "Please pass the (encoded) URL of the Resource you want to fetch!" })
  }

  const data = await getSolidDataset(resource, { fetch: session.fetch })
  res.send(data)
})

When I just execute the session fetch function I get the desired result (as shown below). But all the other solid-client functions require a fetch function to be passed in the options object.

app.get("/fetch", async (req, res) => {
  const session = await getSessionFromStorage(req.session.sessionId);
  const resource = encodeURI("https://warddriesen.solidcommunity.net/private/private_resource")

  if (!session || !session.info.isLoggedIn) {
    return res.status(401)
  }

  if (!resource) {
    return res.status(404).json({ error: "Please pass the (encoded) URL of the Resource you want to fetch!" })
  }

  const result = await (await session.fetch(resource)).text()
  res.send(result)
})

Hopefully someone can help me on this one :slight_smile: !

What is the value of result in that last code snippet? And what do you get if you inspect (await session.fetch(resource)).headers.get("Content-Type")? Possibly it’s not actually a SolidDataset? (If it is, the Content-Type should be something like text/turtle.)

Can you view the resource using Penny? (It uses solid-client behind the scenes.)

1 Like

Hi @Vincent, thanks for the answer.

So this is the source file that I uploaded on my pod:

This is the result of the last code snippet:
–SEE BELOW–

While using Penny I’m not able to read the file:
–SEE BELOW–

Which is kind of weird because I uploaded the same file to my pod hosted on https://warddriesen.inrupt.net, and now with Penny I can read that file (but still not on my pod hosted on https://warddriesen.solidcommunity.net):
–SEE BELOW–

I also tried to fetch the resource from my Inrupt pod with
const data = await getSolidDataset(resource, { fetch: session.fetch }) res.send(data)
But this code snippet also throws the same exception as displayed above.

The content-type of (await session.fetch(resource)).headers.get("Content-Type") is : application/octet-stream

EDIT: this forum won’t let me post more than 1 embedded picture in a comment because I’m a new user, so see the comments below :slight_smile:

This is the result of the last code snippet:

While using Penny I’m not able to read the file:

Which is kind of weird because I also uploaded the same file to my pod hosted on https://warddriesen.inrupt.net, and now with Penny I can read the file (but still not on my pod hosted on https://warddriesen.solidcommunity.net):

I checked on the server your file on https://warddriesen.solidcommunity.net and it is of content-type octet-stream and not text/turtle.
That means it cannot be parsed as text/turtle.

I suppose your first PUT did miss an explicit text/turtle content-type and your function default to octet-stream.
You should remove the resource and reload it using exactly the same function on both servers.
They both use exactly the same NSS v5.6.8.

3 Likes

Thanks a lot @bourgeoa! That solved the issue :slight_smile:

1 Like