Getting Started: Part 1#
This tutorial creates an introductory application that uses Inrupt’s JavaScript client libraries to read your user profile data from your Pod. Alternatively, to create a sample application using Inrupt’s Solid React SDK, refer to Solid React SDK documentation.
The tutorial uses npm and webpack to run the application locally on
localhost:8080
.

Prerequisites#
Register Your Pod and Create Your Profile#
Note
The tutorial assumes that your Pod server is either
https://pod.inrupt.com
or https://inrupt.net/
. If your
example Pod is not on either of these servers, you must change the
oidcIssuer
value in the application’s index.js
file.
For more information on these Pod servers, see Inrupt Pod Spaces.
To create a Pod at https://pod.inrupt.com
(Currently in Alpha):
Go to https://signup.pod.inrupt.com/.
To login or sign up, you must agree to the Inrupt terms of use.
Click Login/Sign Up. You are shown the Login screen.
Click the Sign up link at the bottom to switch to the Sign up screen.
Fill in your username, email, and password.
Click Sign up. You are sent a verification email.
To verify your email, open the verification email and click on the email verification link in the message.
Once verified, go back to Pod Spaces window and click Continue.
Sign in with your username and password.
Click Approve to allow “Inrupt Pod Space Registration” access to requested information. Once approved, your Pod is created:
WebID:
https://pod.inrupt.com/<username>/profile/card#me
Pod URL:
https://pod.inrupt.com/<username>/
Solid Identity Provider:
https://broker.pod.inrupt.com
Click on the Go to PodBrowser link.
At the Pod Browser login screen, click Sign In.
Sign in with your Username and Password.
The consent screen appears. To continue, Approve PodBrowser.
Once logged into PodBrowser, click on your name at the top-right corner and click Profile.
Edit your public profile.
Important
Your profile information is public.
For this tutorial:
Enter a name in the Name field.
Enter a role in the Role field.
Your data is saved automatically.
Log out. Click on your name at the top-right corner and click Log out.
To create a Pod at https://inrupt.net/
:
Open a browser to https://inrupt.net/.
Click Register.
Fill in the form and click Register. Your Pod is created:
Pod URL
https://<yourusername>.inrupt.net
WebID:
https://<username>.inrupt.net/profile/card#me
Solid Identity Provider:
https://inrupt.net
You are redirected to your public Solid Pod URL:
https://<yourusername>.inrupt.net
.Click Log in on the upper right corner.
From the list of identity providers, click on your Solid Pod URL.
Enter your Username and Password and click Log in.
Click on the Edit your profile tab.
Tip
You may need to reload the page.
Edit your public profile.
Important
Your profile information is public.
For this tutorial:
Enter a name in the Name field.
Enter a role in the Role field.
Your data is saved automatically.
Log out. Move your mouse to the image in the upper-right corner image to display additional menu items and click Log out.
Install npm
#
If you do not already have npm installed, install npm. npm
is installed as part of the
Node.js installation.
Ensure that you use a version of Node that is supported by webpack. For webpack 5, the minimum Node version is version 10.13.0(LTS).
Build the Application#
1. Initialize the Application#
Create the directory structure for your Webpack project:
mkdir -p my-demo-app my-demo-app/src my-demo-app/dist
Go to the newly created
my-demo-app
directory.cd my-demo-app
Initialize the application.
To accept the default values for the application without prompts:
npm init -y
- or -
To be prompted to enter values for the application:
npm init
You can either hit return to accept the default values (including empty values) or supply your own values.
When prompted
Is this OK? (yes)
, enter to acceptyes
.
2. Install the Client Libraries and Polyfill#
Use
npm
to install thesolid-client
,solid-client-authn-browser
, andvocab-common-rdf
libraries:npm install @inrupt/solid-client @inrupt/solid-client-authn-browser @inrupt/vocab-common-rdf
For the browser application, install the polyfill for
buffer
:npm install buffer
3. Install Webpack#
Use
npm
to install Webpack packages:npm install webpack webpack-cli webpack-dev-server css-loader style-loader --save-dev
In
my-demo-app
directory, create awebpack.config.js
file with the following content:const path = require("path"); module.exports = { mode: "development", entry: "./src/index.js", output: { path: path.resolve(__dirname, "dist"), filename: "index.js" }, module: { rules: [ { test: /\.css$/, use: [ { loader: "style-loader" }, { loader: "css-loader" } ], }, ] }, devServer: { static: "./dist" } };
In
my-demo-app
directory, edit thepackage.json
file to addbuild
andstart
script fields toscripts
:Tip
Be sure to add the comma after the preceding field value before adding the
build
andstart
fields."scripts": { "test": "echo \"Error: no test specified\" && exit 1", "build": "webpack", "start": "webpack serve --open" },
4. Create the Application#
In the my-demo-app
directory, create the files for the application.
For an explanation of the JavaScript code used in this tutorial, see
Examination of the Code.
In the
my-demo-app/dist
folder, create amy-demo.css
file with the following content:h2,h3 { margin: 1rem 1.2rem 1rem 1.4rem; } body * { margin-left: .5rem; margin-right: 1rem; } header { border-bottom: #5795b9 solid; padding-left: .5rem; } .panel { border: 1px solid #005b81; border-radius: 4px; box-shadow: rgb(184, 196, 194) 0px 4px 10px -4px; box-sizing: border-box; padding: 1rem 1.5rem; margin: 1rem 1.2rem 1rem 1.2rem; } #login { background: white; } #read { background: #e6f4f9; } #labelStatus[role="alert"] { padding-left: 1rem; color: purple; } .display { margin-left: 1rem; color: gray; } dl { display: grid; grid-template-columns: max-content auto; } dt { grid-column-start: 1; } dd { grid-column-start: 2; }
In the
my-demo-app/dist
, create anindex.html
file with the following content:<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Getting Started: Inrupt JavaScript Client Libraries</title> <script defer src="./index.js" ></script> <link rel="stylesheet" href="my-demo.css" /> </head> <body> <header> <h2>Getting Started</h2> <h3>with Inrupt JavaScript Client Libraries</h3> </header> <section id="login" class="panel"> <div class="row"> <label id="labelLogin" for="btnLogin">1. Click the button to log in: </label> <button name="btnLogin" id="btnLogin">Login</button> <p id="labelStatus"></p> </div> </section> <div id="read" class="panel" > <div class="row"> <label id="readlabel" for="webID">2. Enter a WebID: </label> <input type="url" id="webID" name="webID" size="50" pattern="https://.*" value="https://pod.inrupt.com/<username>/profile/card#me"> <button name="btnRead" id="btnRead" >Read Profile</button> </div> <dl class="display"> <dt>Profile SolidDataset: </dt> <dd id="labelProfile"></dd> <dt>Formatted Name (FN): </dt> <dd id="labelFN"></dd> <dt>Role: </dt> <dd id="labelRole"></dd> </dl> </div> </body> </html>
In the
my-demo-app/src
, create anindex.js
file with the following content:Note
If your Pod is not on
https://pod.inrupt.com
, modify theoidcIssuer
value.// Import from "@inrupt/solid-client-authn-browser" import { login, handleIncomingRedirect, getDefaultSession, fetch } from "@inrupt/solid-client-authn-browser"; // Import from "@inrupt/solid-client" import { getSolidDataset, getThing, getStringNoLocale } from "@inrupt/solid-client"; import { VCARD, FOAF } from "@inrupt/vocab-common-rdf"; const buttonLogin = document.querySelector("#btnLogin"); const buttonRead = document.querySelector("#btnRead"); // 1a. Start Login Process. Call login() function. function loginToInruptDotCom() { return login({ oidcIssuer: "https://broker.pod.inrupt.com", redirectUrl: window.location.href, clientName: "Getting started app" }); } // 1b. Login Redirect. Call handleIncomingRedirect() function. // When redirected after login, finish the process by retrieving session information. async function handleRedirectAfterLogin() { await handleIncomingRedirect(); const session = getDefaultSession(); if (session.info.isLoggedIn) { // Update the page with the status. document.getElementById("labelStatus").textContent = "Your session is logged in."; document.getElementById("labelStatus").setAttribute("role", "alert"); } } // The example has the login redirect back to the index.html. // This calls the function to process login information. // If the function is called when not part of the login redirect, the function is a no-op. handleRedirectAfterLogin(); // 2. Read profile async function readProfile() { const webID = document.getElementById("webID").value; // The example assumes the WebID has the URI <profileDocumentURI>#<fragment> where // <profileDocumentURI> is the URI of the SolidDataset // that contains profile data. // Parse ProfileDocument URI from the `webID` value. const profileDocumentURI = webID.split('#')[0]; document.getElementById("labelProfile").textContent = profileDocumentURI; // Use `getSolidDataset` to get the Profile document. // Profile document is public and can be read w/o authentication; i.e.: // - You can either omit `fetch` or // - You can pass in `fetch` with or without logging in first. // If logged in, the `fetch` is authenticated. // For illustrative purposes, the `fetch` is passed in. const myDataset = await getSolidDataset(profileDocumentURI, { fetch: fetch }); // Get the Profile data from the retrieved SolidDataset const profile = getThing(myDataset, webID); // Get the formatted name using `FOAF.name` convenience object. // `FOAF.name` includes the identifier string "http://xmlns.com/foaf/0.1/name". // As an alternative, you can pass in the "http://xmlns.com/foaf/0.1/name" string instead of `FOAF.name`. const fn = getStringNoLocale(profile, FOAF.name); // Get the role using `VCARD.role` convenience object. // `VCARD.role` includes the identifier string "http://www.w3.org/2006/vcard/ns#role" // As an alternative, you can pass in the "http://www.w3.org/2006/vcard/ns#role" string instead of `VCARD.role`. const role = getStringNoLocale(profile, VCARD.role); // Update the page with the retrieved values. document.getElementById("labelFN").textContent = fn; document.getElementById("labelRole").textContent = role; } buttonLogin.onclick = function() { loginToInruptDotCom(); }; buttonRead.onclick = function() { readProfile(); };
In the
my-demo-app/dist
folder, create amy-demo.css
file with the following content:h2,h3 { margin: 1rem 1.2rem 1rem 1.4rem; } body * { margin-left: .5rem; margin-right: 1rem; } header { border-bottom: #5795b9 solid; padding-left: .5rem; } .panel { border: 1px solid #005b81; border-radius: 4px; box-shadow: rgb(184, 196, 194) 0px 4px 10px -4px; box-sizing: border-box; padding: 1rem 1.5rem; margin: 1rem 1.2rem 1rem 1.2rem; } #login { background: white; } #read { background: #e6f4f9; } #labelStatus[role="alert"] { padding-left: 1rem; color: purple; } .display { margin-left: 1rem; color: gray; } dl { display: grid; grid-template-columns: max-content auto; } dt { grid-column-start: 1; } dd { grid-column-start: 2; }
In the
my-demo-app/dist
, create anindex.html
file with the following content:<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Getting Started: Inrupt JavaScript Client Libraries</title> <script defer src="./index.js" ></script> <link rel="stylesheet" href="my-demo.css" /> </head> <body> <header> <h2>Getting Started</h2> <h3>with Inrupt JavaScript Client Libraries</h3> </header> <section id="login" class="panel"> <div class="row"> <label id="labelLogin" for="btnLogin">1. Click the button to log in: </label> <button name="btnLogin" id="btnLogin">Login</button> <p id="labelStatus"></p> </div> </section> <div id="read" class="panel" > <div class="row"> <label id="readlabel" for="webID">2. Enter a WebID: </label> <input type="url" id="webID" name="webID" size="50" pattern="https://.*" value="https://docs-example.inrupt.net/profile/card#me"> <button name="btnRead" id="btnRead" >Read Profile</button> </div> <dl class="display"> <dt>Profile SolidDataset: </dt> <dd id="labelProfile"></dd> <dt>Formatted Name (FN): </dt> <dd id="labelFN"></dd> <dt>Role: </dt> <dd id="labelRole"></dd> </dl> </div> </body> </html>
In the
my-demo-app/src
, create anindex.js
file with the following content:Note
If your Pod is not on
https://inrupt.net
, modify theoidcIssuer
value.import { getSolidDataset, getThing, getStringNoLocale } from "@inrupt/solid-client"; import { login, handleIncomingRedirect, getDefaultSession, fetch } from "@inrupt/solid-client-authn-browser"; import { VCARD } from "@inrupt/vocab-common-rdf"; const buttonLogin = document.querySelector("#btnLogin"); const buttonRead = document.querySelector("#btnRead"); // 1a. Start Login Process. Call login() function. function loginToInruptDotNet() { return login({ oidcIssuer: "https://inrupt.net", redirectUrl: window.location.href, clientName: "Getting started app" }); } // 1b. Login Redirect. Call handleIncomingRedirect() function. // When redirected after login, finish the process by retrieving session information. async function handleRedirectAfterLogin() { await handleIncomingRedirect(); const session = getDefaultSession(); if (session.info.isLoggedIn) { // Update the page with the status. document.getElementById("labelStatus").textContent = "Your session is logged in."; document.getElementById("labelStatus").setAttribute("role", "alert"); } } // The example has the login redirect back to the index.html. // This calls the function to process login information. // If the function is called when not part of the login redirect, the function is a no-op. handleRedirectAfterLogin(); // 2. Read profile async function readProfile() { const webID = document.getElementById("webID").value; // The example assumes the WebID has the URI <profileDocumentURI>#<fragment> where // <profileDocumentURI> is the URI of the SolidDataset // that contains profile data. // Parse ProfileDocument URI from the `webID` value. const profileDocumentURI = webID.split('#')[0]; document.getElementById("labelProfile").textContent = profileDocumentURI; // Use `getSolidDataset` to get the Profile document. // Profile document is public and can be read w/o authentication; i.e.: // - You can either omit `fetch` or // - You can pass in `fetch` with or without logging in first. // If logged in, the `fetch` is authenticated. // For illustrative purposes, the `fetch` is passed in. const myDataset = await getSolidDataset(profileDocumentURI, { fetch: fetch }); // Get the Profile data from the retrieved SolidDataset const profile = getThing(myDataset, webID); // Get the formatted name (fn) using the property identifier "http://www.w3.org/2006/vcard/ns#fn". // VCARD.fn object is a convenience object that includes the identifier string "http://www.w3.org/2006/vcard/ns#fn". // As an alternative, you can pass in the "http://www.w3.org/2006/vcard/ns#fn" string instead of VCARD.fn. const fn = getStringNoLocale(profile, VCARD.fn); // VCARD.role object is a convenience object that includes the identifier string "http://www.w3.org/2006/vcard/ns#role" // As an alternative, you can pass in the "http://www.w3.org/2006/vcard/ns#role" string instead of VCARD.role. const role = getStringNoLocale(profile, VCARD.role); // Update the page with the retrieved values. document.getElementById("labelFN").textContent = fn; document.getElementById("labelRole").textContent = role; } buttonLogin.onclick = function() { loginToInruptDotNet(); }; buttonRead.onclick = function() { readProfile(); };
For details about the JavaScript code, see Examination of the Code.
5. Run the Application#
In the
my-demo-app
directory, run:npm run build && npm run start
The output resembles the following:
ℹ 「wds」: Project is running at http://localhost:8080/ ... ℹ 「wdm」: Compiled successfully.
Open
localhost:8080
in a browser.Login.
Click Login to login.
If you have logged out of your Pod, you are prompted to log in. Enter your username and password and log in.
For pod.inrupt.com, you will be prompted to approve this application’s access to the requested information. To continue, click Approve.
For inrupt.net, you will be prompted to authorize applications from
http://localhost:8080
to access your Pod.You are redirected back to your page.
Read public profile data.
Note
Because the profile data is public, you do not need to log in to read the data. The application does so to show how to make authenticated read requests.
Enter your WebID. The application assumes WebID of the form
<profileDocumentURI>#<fragment>
and parses theprofileDocumentURI
from the entered WebID. 1Click Read Profile.
The page should display your formatted name and role.
You can read public profiles of others by entering in their WebID; e.g.,
https://pod.inrupt.com/docsteam/profile/card#me
.
6. Exit the Application#
To exit the application, stop the npm run start
process; e.g.,
Ctrl-C
.
Explanation of the Code#
See Examination of the Code for an explanation of the Inrupt’s JavaScript client libraries usage in this tutorial.
Additional Information#
API Documentation#
React SDK Availability#
To create a sample application using Inrupt’s Solid React SDK, refer to the Solid React SDK documentation.
- 1
Although the example assumes that the WebID has the URI
<profileDocumentURI>#<fragment>
, a WebID can also have a URL without the hash fragment. For details, see https://www.w3.org/2005/Incubator/webid/spec/identity/#dfn-webid.