2 - Authenticating the user

💡
The class names in these snippets are left in case you would like to use the stylesheets available in the repository.

Using the LoginButton component to log users in

The first thing we need to do in order to be able to write to our Pod is to authenticate as a user with write permissions, so we have the permissions to do so. Luckily, with the login button from solid-ui-react this is very straightforward.

We need to import LoginButton from solid-ui-react. This component accepts two required props: oidcIssuer, the Pod provider, which in our case will be https://broker.pod.inrupt.com/, and a redirectUrl which is the URL we want to be redirected to after we login.

The LoginButton also takes an optional authOptions prop, which is an object with the clientName property. This is useful because we want to display our app's name to the user when they authenticate. If we don't pass the clientName, a random string will be generated which is confusing for the user when they're granting our app permission to do things.

In App.js let's get rid of all the boilerplate that comes with our React app and use the LoginButton:

// App.js

import React from "react";
import { LoginButton } from "@inrupt/solid-ui-react";

const authOptions = {
    clientName: "Solid Todo App",
  };

function App() {
  return (
    <div className="app-container">
      <LoginButton
          oidcIssuer="https://broker.pod.inrupt.com/"
          redirectUrl={window.location.href}
          authOptions={authOptions}
       />
    </div>
  );
}

export default App;

In the index.js file, let's wrap our App component with the SessionProvider component. Now, we can use the useSession hook throughout the entire app, which returns session info that allows us to make authenticated requests.

Replace the boilerplate in index.js with the following:

// index.js

import ReactDOM from "react-dom";
import App from "./App";
import { SessionProvider } from "@inrupt/solid-ui-react";

ReactDOM.render(
  <SessionProvider>
    <App />
  </SessionProvider>,
  document.getElementById("root")
);

Once that is done, you can test it! Run your app with npm start and click on the Login button. It should take you to a page where you can either log in or register. If you don't have an account, you can click on "Sign up" to create one. Once you log in, you will be redirected to the main page. As you can see, our main page only has the login button. We are logged in, but we don't do anything with that information. Let's change that!

Using profile data

We're going to change our code so our app shows the login button if we're logged out, and our name if we're logged in.

For this we're going to use CombinedDatasetProvider and Text from solid-ui-react. CombinedDatasetProvider needs two props: datasetUrl and thingUrl, which, in this case, can be both set to the user's WebID.

💡
A WebID is an HTTP URI which refers to an agent (for example, a person), that, when looked up, resolves to a profile document.

CombinedDatasetProvider fetches the dataset and Thing for us so we can pass it straight on to the children.

The child in our app will be the Text component

The Text component takes a prop, either property or properties, that specifies the value to retrieve and display from the fetched dataset/thing. In our case, we want the Text component to retrieve and display the name of the user from the user's profile. property or properties is the URL or URLs we have chosen for the predicate for which we want to fetch the data.

In our case we want to get the name of the user.

💡
A user's profile data is stored as Resource Description Framework (RDF) data. RDF is a standard model for data interchange on the Web. RDF data is stored in triples, which are composed of a subject, a predicate and an object. So, for instance, if I want to write a social networking app and I want to store Bob's acquaintances, I could add one like so: <http://example.org/bob#me> <http://xmlns.com/foaf/0.1/knows> <http://example.org/alice#me> . where <http://example.org/bob#me> is the subject, <http://xmlns.com/foaf/0.1/knows> is the predicate and <http://example.org/alice#me> is the object.

To specify that we want to retrieve the name, we use a name identifier. In our example, we use a name identifier from an existing Vocabulary.

💡
Vocabularies are collections of identifiers (URIs) with a clearly defined meaning. An example of a popular vocabulary is FOAF (Friend Of A Friend), which defines URIs to describe people and their relationships. You can find more information about vocabularies in the Solid Project website.

The name of the logged in user, in most cases, will be stored in the profile document under "http://www.w3.org/2006/vcard/ns#fn" or "http://xmlns.com/foaf/0.1/name". fn stands for formatted name. In RDF, that looks like this:

:me <http://www.w3.org/2006/vcard/ns#fn> "Virginia Balseiro" .

or

:me <http://xmlns.com/foaf/0.1/name> "Virginia Balseiro" 

But in our case we want it to check under http://www.w3.org/2006/vcard/ns#fn and if it cannot find anything, check under http://xmlns.com/foaf/0.1/name. We can use properties, which is an array of properties to attempt to read from, in our Text component.

// App.js

import React from "react";
import {
  LoginButton,
  Text,
  useSession,
  CombinedDataProvider,
} from "@inrupt/solid-ui-react";

const authOptions = {
    clientName: "Solid Todo App",
  };

function App() {
  const { session } = useSession();
  return (
    <div className="app-container">
      {session.info.isLoggedIn ? (
        <CombinedDataProvider
          datasetUrl={session.info.webId}
          thingUrl={session.info.webId}
        >
          <div className="message logged-in">
            <span>You are logged in as: </span>
            <Text properties={[
                "http://www.w3.org/2006/vcard/ns#fn",
                "http://xmlns.com/foaf/0.1/name",
              ]} />
          </div>
        </CombinedDataProvider>
      ) : (
        <div className="message">
          <span>You are not logged in. </span>
          <LoginButton
            oidcIssuer="https://broker.pod.inrupt.com/"
            redirectUrl={window.location.href}
						authOptions={authOptions}
          />
        </div>
      )}
    </div>
  );
}

export default App;

We can now log in and display info from our Pod in our app.

Logging users out

Let's now add a logout button so we can log out whenever we want to. This is easy: we just need to import the LogoutButton from solid-ui-react and display it underneath the Text with the user name:

// App.js

import {
  LoginButton,
  LogoutButton,
  Text,
  useSession,
  CombinedDataProvider,
} from "@inrupt/solid-ui-react";

function App() {
  const { session } = useSession();

	// ...
	
	<div className="message logged-in">
	  <span>You are logged in as: </span>
	  <Text properties={[
	     "http://xmlns.com/foaf/0.1/name",
	     "http://www.w3.org/2006/vcard/ns#fn",
	   ]} />    
	   <LogoutButton />
	 </div>

	// ...

}
💡
Commit: d206fe2

3 - Create a to-do