All libraries and documentation are currently in Beta. Content and features are subject to change.

Getting Started

This tutorial creates an introductory application that uses Inrupt’s JavaScript client libraries to read your user profile data. Alternatively, to create a sample application using Inrupt’s Solid React SDK, refer to Solid React SDK documentation.

The tutorial uses npm and Parcel to run the application locally on localhost:1234.

Locally Run Getting Started Application

Prerequisites

Register Your Pod and Create Your Profile

If you do not already have a Pod:

  1. Open a browser to https://inrupt.net/.

  2. Click Register.

  3. Fill in the form and click Register.

    You are redirected to your public Solid Pod URL: https://<yourusername>.inrupt.net.

  4. Click Log in on the upper right corner.

  5. From the list of identity providers, click on your Solid Pod URL.

  6. Enter your Username and Password and click Log in.

  7. Click on the Edit your profile tab.

    Tip

    You may need to reload the page.

  8. Edit your public profile.

    Important

    Your profile information is public.

    For this tutorial:

    1. Enter a name in the Name field.

    2. Enter a role in the Role field.

    Your data is saved automatically.

  9. 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.

Build the Application

1. Initialize the Application

  1. Create a directory for the project:

    mkdir my-demo-app
    
  2. Go to the newly created directory.

    cd my-demo-app
    
  3. Initialize the application:

    npm init
    
    1. During initialization, you can either hit return to accept the default values (including empty values) or supply your own values.

    2. When prompted Is this OK? (yes), enter to accept yes.

2. Install Parcel

  1. Use npm to install Parcel:

    npm install parcel-bundler
    
  2. Edit the package.json file to list the browsers supported by this application. Specifically, add the browserslist field and value:

    Tip

    Be sure to add the comma after the preceding field before adding the browserslist field.

    "dependencies": {
       ...
    },
    "browserslist": [
      "last 3 and_chr versions",
      "last 3 chrome versions",
      "last 3 opera versions",
      "last 3 ios_saf versions",
      "last 3 safari versions",
      "last 3 edge versions"
    ]
    

    Without the browserslist specification, Parcel would need to inject a compatibility layer to avoid a regeneratorRuntime reference error since the sample application uses async functions. As an alternative to modifying the package.json file, you could import regenerator-runtime/runtime in your JavaScript code to inject a compatibility layer.

3. Create the Application

In the my-demo-app directory, create the files for the application. The tutorial provides an explanation of the JavaScript code at the end of the tutorial.

  1. Create the my-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;
    }
    
  2. Create an index.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>Formatted Name (FN): </dt>
              <dd id="labelFN"></dd>
              <dt>Role: </dt>
              <dd id="labelRole"></dd>
          </dl>
        </div>
      </body>
    </html>
    
  3. Create an index.js file with the following content:

    import {
      getSolidDataset,
      getThing,
      getStringNoLocale
    } from "@inrupt/solid-client";
    
    import {
      Session,
      getClientAuthenticationWithDependencies
    } from "@inrupt/solid-client-authn-browser";
    
    import { VCARD } from "@inrupt/vocab-common-rdf";
    
    
    const session = new Session({
      clientAuthentication: getClientAuthenticationWithDependencies({})},
      "mySession"
    );
    
    const buttonLogin = document.querySelector('#btnLogin');
    const buttonRead = document.querySelector('#btnRead');
    
    // 1a. Start Login Process. Call session.login() function.
    async function login() {
      if ( !session.info.isLoggedIn && !new URL(window.location.href).searchParams.get("code")) {
        await session.login({
          oidcIssuer: 'https://inrupt.net',
          redirectUrl: 'http://localhost:1234',
        });
      }
    }
    
    // 1b. Login Redirect. Call session.handleIncomingRedirect() function.
    // When redirected after login, finish the process by retrieving session information.
    async function handleRedirectAfterLogin() {
      // If redirected, has code
      if (new URL(window.location.href).searchParams.get("code")) {
        await session.handleIncomingRedirect(window.location.href);
    
        // 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;
    
      // Profile is public data; i.e., you do not need to be logged in to read the data.
      // For illustrative purposes, shows both an authenticated and non-authenticated reads.
    
      let myDataset;
      if (session.isLoggedIn){
        myDataset = await getSolidDataset(webID, { fetch: session.fetch });
      } else {
        myDataset = await getSolidDataset(webID);
      }
    
      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 obect 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() {  
      login();
    };
    
    buttonRead.onclick = function() {  
      readProfile();
    };
    

    For details about the JavaScript code, see Examination of the Code.

4. Run the Application

  1. In the my-demo-app directory, run:

    npx parcel index.html
    

    The output resembles the following:

    Server running at http://localhost:1234
    ...
    Built in 2ms.
    

    If there are warnings with regards to the various source maps, you can ignore them.

  2. Open localhost:1234 in a browser.

  3. Login.

    1. Click Login to login.

    2. If you have logged out of your Pod, you are prompted to log in. Enter your username and password and log in.

    3. You will be prompted to authorize http://localhost:1234 to access your Pod. To allow the application to read and write to your Pod, click Authorize.

    4. You are redirected back to your page.

    Tip

    If you encounter redirect issues trying to log in, you may need to clear the cache.

  4. 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.

    1. Enter your WebID (e.g., https://<username>.inrupt.net/profile/card#me).

    2. Click Read Profile.

    3. The page should display your formatted name and role.

    You can read public profiles of others by entering in their WebID; e.g., https://docs-example.inrupt.net/profile/card#me.

5. Exit the Application

To exit the application, stop the npx parcel process; e.g., Ctrl-C.

Examination of the Code

Login Code

The example uses the solid-client-authn-browser library to log in. solid-client-authn-browser is for client-side code only.

From @inrupt/solid-client-authn-browser, import Session and getClientAuthenticationWithDependencies:

import {
  Session,
  getClientAuthenticationWithDependencies
} from "@inrupt/solid-client-authn-browser";

Create a new Session:

const session = new Session({
  clientAuthentication: getClientAuthenticationWithDependencies({})},
  "mySession"
);

Start the login process by calling Session.login():

// 1a. Start Login Process. Call session.login() function.
async function login() {
  if ( !session.info.isLoggedIn && !new URL(window.location.href).searchParams.get("code")) {
    await session.login({
      oidcIssuer: 'https://inrupt.net',
      redirectUrl: 'http://localhost:1234',
    });
  }
}

This function sends the user to the identity provider oidcIssuer, and once logged in, redirects back to the specified redirectURL.

When redirected back from the identity provider, use Session.handleIncomingRedirect() to complete the login process:

// 1b. Login Redirect. Call session.handleIncomingRedirect() function.
// When redirected after login, finish the process by retrieving session information.
async function handleRedirectAfterLogin() {
  // If redirected, has code
  if (new URL(window.location.href).searchParams.get("code")) {
    await session.handleIncomingRedirect(window.location.href);

    // 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();

The function collects the information provided by the identity provider.

For more information on using the library to authenticate, see Authenticate.

Read Profile Code

The example uses the solid-client and vocab-common-rdf libraries to read profile data from a Pod.

From @inrupt/solid-client and @inrupt/vocab-common-rdf, import the objects used in the application:

import {
  getSolidDataset,
  getThing,
  getStringNoLocale
} from "@inrupt/solid-client";
import { VCARD } from "@inrupt/vocab-common-rdf";

Use getSolidDataset to fetch the SolidDataset from the URI.

  let myDataset;
  if (session.isLoggedIn){
    myDataset = await getSolidDataset(webID, { fetch: session.fetch });
  } else {
    myDataset = await getSolidDataset(webID);
  }
  1. For authenticated reads, pass in the URI and the session’s fetch function as an option.

  2. For unauthenticated reads, pass in the URI.

Although the application uses a URI that contains a fragment (i.e. the URI of a Thing), the returned SolidDataset is the resource located at the URI w/o the fragment. That is, if the URI is https://<username>.inrupt.net/profile/card#me, the returned SolidDataset is the resource at https://<username>.inrupt.net/profile/card. You can modify the application to pass in the resource URI https://<username>.inrupt.net/profile/card instead.

From the fetched SolidDataset, the application uses the getThing to retrieve the profile. A Thing’s URI contains a fragment, as in #me in https://<username>.inrupt.net/profile/card#me.

  const profile = getThing(myDataset, webID);

The application uses getStringNoLocale to retrieve:

  • the formatted name (fn) property stored with the identifier http://www.w3.org/2006/vcard/ns#fn, and

  • the role (role) property stored with the identifier http://www.w3.org/2006/vcard/ns#role.

  // 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 obect 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);

The application uses VCARD.fn and VCARD.role convenience objects from the vocab-common-rdf library to specify the property identifiers.

Additional Information

React SDK Availability

To create a sample application using Inrupt’s Solid React SDK, refer to the Solid React SDK documentation.