Skip to content

Usage Examples

Christoph Braun edited this page Nov 6, 2025 · 7 revisions

You can use this library along the lines of these examples:

in a Single Page Application (SPA)

Vue

I use Vue for my apps. If you want to see how this library is used in a Vue app, look at my Solid App Template (Vue Edition). It should (TM) work the same with the other frameworks. Here is a quick usage example:

Defining a useSolidSession composable e.g. located in ./composables/useSolidSession

import { DynamicRegistrationClientDetails, Session, SessionEvents, SessionExpirationWarningDetail, SessionOptions, SessionStateChangeDetail } from "@uvdsl/solid-oidc-client-browser";
import { Reactive, reactive, readonly } from "vue";

interface SessionState {
  isActive: boolean;
  webId?: string;
  isLoading: boolean;
}

// This reactive object holds the global session state. Components can
// subscribe to this state and will automatically update when it changes.
const sessionState: Reactive<SessionState> = reactive({
  isActive: false,
  webId: undefined,
  isLoading: true,
});

// This handler syncs the external session's state with our reactive Vue state.
const handleStateChange = (event: Event) => {
  if (event instanceof CustomEvent) {
    const { isActive, webId } = event.detail as SessionStateChangeDetail;
    // Any event from the session means the loading phase is complete.
    sessionState.isActive = isActive;
    sessionState.webId = webId;
    sessionState.isLoading = false;
  }
};

// This handler warns about session expiration
const handleExpirationWarning = (event: Event) => {
  if (event instanceof CustomEvent) {
    const { expires_in } = event.detail as SessionExpirationWarningDetail;
    console.warn(`[WARN] Session will expire in ${expires_in}s.`);
  }
};

// This handler ends the session on expiration
const handleExpiration = (event: Event) => {
  if (event instanceof CustomEvent) {
    sessionState.isActive = false;
    sessionState.webId = undefined;
    sessionState.isLoading = false;
  }
};

// example client details
const clientDetails: DynamicRegistrationClientDetails = {
  redirect_uris: [window.location.href],
  client_name: "My Solid App"
};

// Option 1: pass event listeners as session options
const sessionOptions = {
  workerUrl: refreshWorkerUrl,
  onSessionStateChange: handleStateChange,
  onSessionExpirationWarning: handleExpirationWarning,
  onSessionExpiration: handleExpiration
} as SessionOptions

// It's recommended to create a single session instance 
// that the entire application can share.
const session = new Session(clientDetails, sessionOptions);

// Option 2: pass (additional) event listeners dynamically after session creation (uncomment if wanted)
// session.addEventListener(SessionEvents.STATE_CHANGE, handleStateChange);
// session.addEventListener(SessionEvents.EXPIRATION_WARNING, handleExpirationWarning);
// session.addEventListener(SessionEvents.EXPIRATION, handleExpiration);

// This function handles the initial, asynchronous session restoration.
// It is called only once when this module is first imported.
const initializeSession = async () => {
  try {
    await session.restore();
  } catch (e) {
    // This is an expected outcome if no previous session exists.
  } finally {
    // This block is crucial. It ensures `isLoading` is set to false
    // and the state is synchronized after the restore attempt, even if
    // `restore()` fails silently and doesn't fire a `stateChange` event.
    sessionState.isActive = session.isActive;
    sessionState.webId = session.webId;
    sessionState.isLoading = false;
  }
};

// Start the session restoration process immediately.
initializeSession();


/**
 * A Vue Composable to provide access to the global session state and instance.
 * @returns An object with the reactive state (readonly) and the session instance.
 */
export function useSolidSession() {
  return {
    // It's a best practice to return a readonly version of the state
    // to prevent components from directly modifying it.
    state: readonly(sessionState),
    // The session instance is provided for calling methods like login() or logout().
    session,
  };
}

Usage in a component, e.g. with a login button, logout button, ...

import { useSolidSession } from './composables/useSolidSession';
const { session, state } = useSolidSession();

// call on a button click
const redirect_uri = window.location.href;
const idp = "your IDP";
session.login(idp, redirect_uri);

// in code that is being executed
// to handle the redirect after login
session.handleRedirectFromLogin();
// let's have a look if we have a session
watch(() => state.isActive, () => console.log("Logged in:", state.webId), { immediate: true });

// call on a button click
session.logout();

React

import { useState, useEffect } from 'react';
import { Session, SessionEvents, SessionStateChangeDetail } from '@uvdsl/solid-oidc-client-browser';

// It's recommended to create a single, global session instance that the
// entire application can share.
const session = new Session(clientDetails);

/**
 * A custom React Hook to subscribe to the session state.
 * It handles the initial session restoration and provides reactive
 * session data and a loading status.
 * @returns An object with { isActive, webId, isLoading }.
 */
function useSession() {
  const [sessionData, setSessionData] = useState({
    isActive: false,
    webId: undefined,
    // The isLoading flag prevents UI flicker while the initial,
    // asynchronous session restoration is in progress.
    isLoading: true,
  });

  useEffect(() => {
    // This handler syncs the external session's state with our internal React state.
    const handleStateChange = (event: Event) => {
      if (event instanceof CustomEvent) {
        const { isActive, webId } = event.detail as SessionStateChangeDetail;
        // Any event from the session means the loading phase is complete.
        setSessionData({ isActive, webId, isLoading: false });
      }
    };

    session.addEventListener(SessionEvents.STATE_CHANGE, handleStateChange);

    // This function handles the initial, asynchronous session restoration.
    const initializeSession = async () => {
      try {
        await session.restore();
      } catch (e) {
        // This is an expected outcome if no previous session exists.
      } finally {
        // This block is crucial. It ensures `isLoading` is set to false
        // and the state is synchronized after the restore attempt, even if
        // `restore()` fails silently and doesn't fire a `stateChange` event.
        setSessionData({
          isActive: session.isActive,
          webId: session.webId,
          isLoading: false,
        });
      }
    };

    initializeSession();

    // The cleanup function removes the event listener when the component unmounts
    // to prevent memory leaks.
    return () => {
      session.removeEventListener(SessionEvents.STATE_CHANGE, handleStateChange);
    };
  }, []); // The empty dependency array ensures this effect runs only once.

  return sessionData;
}

After logging in ...

Once authenticated, you can use session.authFetch to fetch data from the Web using authenticated requests. If the session is not yet authenticated, session.authFetch behaves like window.fetch.

There is a small library that provides Solid Requests for get, post, put, delete on resources, and even to create resources with the correct LDP link header, and to create containers with the correct link header - for your convenience.

If you don't want to dabble with parsing the retrieved RDF data manually, check out the Solid RDF Store. You can use the session object in that store to let the store fetch (authenticated) RDF data from the Web and have reactive query results, i.e. results that can update reactively when query underlying data changes.

via CDN (strongly discouraged! only use for quick testing)

Please note the corresponding security considerations. Currently, your best option for playing around is version 0.1.3. See also this worker-related issue.

in a simple HTML page with JavaScript

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Solid Login Page</title>
    <script type="module" src="https://unpkg.com/@uvdsl/solid-oidc-client-browser@0.1.3/dist/esm/index.min.js"></script>
</head>

<body>
    <div class="container">
        <h1>Solid Login Demo</h1>
        <p>Click the button below to log in with your Solid identity provider (solidcommunity.net)</p>
        <p id="welcome-message">Welcome to the application</p>
        <div id="user-info" class="user-info">
            <p>WebID: <span id="webid">not logged in.</span></p>
        </div>
        <button id="loginButton">Login with Solid</button>
        <button id="logoutButton">Logout</button>
    </div>

    <script>
       // Initialize the session
        let session;

        document.addEventListener('DOMContentLoaded', async () => {
            const module = await import('https://unpkg.com/@uvdsl/solid-oidc-client-browser@0.1.3/dist/esm/index.min.js');
            const Session = module.Session;

            const sessionOptions = {
                onSessionStateChange: () => {
                    console.warn("Session state changed!");
                    document.getElementById('webid').textContent = session.webId;
                    document.getElementById('welcome-message').textContent =
                        `State was updated.`;
                },
                onSessionExpirationWarning: () => {
                    console.warn("Session is about to expire!");
                    document.getElementById('welcome-message').textContent = "Warning: Session is expiring soon.";
                },
                onSessionExpiration: () => {
                    console.warn("Session is expired!");
                    document.getElementById('webid').textContent = "not logged in.";
                    document.getElementById('welcome-message').textContent =
                        "You're not logged in.";
                }
            };

            // Create a new session
            const clientDetails  = {
                redirect_uris: [window.location.href],
                client_name: "uvdsl's Solid App Template"
            };
            session = new Session(clientDetails, sessionOptions);


            // Set up the login button
            document.getElementById('loginButton').addEventListener('click', () => {
                const idp = "https://solidcommunity.net/";
                const redirect_uri = window.location.href; // The URL of this page
                session.login(idp, redirect_uri);
            });

            // Set up the logout button
            document.getElementById('logoutButton').addEventListener('click', () => {
                session.logout();
                document.getElementById('webid').textContent = "not logged in.";
                document.getElementById('welcome-message').textContent =
                    "You're not logged in.";
            });

            // Handle page revisit
            try {
                // either: handle redirect after login
                await session.handleRedirectFromLogin();
                // or: try to restore the session
                await session.restore().catch(e => console.log(e.message));

                if (session.webId) {
                    document.getElementById('webid').textContent = session.webId;
                    document.getElementById('welcome-message').textContent =
                        `Welcome! You are logged in.`;
                } else {
                    document.getElementById('welcome-message').textContent =
                        "You're not logged in.";
                }
            } catch (error) {
                console.error("Error restoring session:", error);
                document.getElementById('welcome-message').textContent =
                    "Error restoring session. Please try logging in again.";
            }
        });
    </script>
</body>

</html>

in a simple Multi Page Application with JavaScript

Just serve the two files on a web server.

index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Solid Login Page</title>
    <script type="module" src="https://unpkg.com/@uvdsl/solid-oidc-client-browser@0.1.3/dist/esm/index.min.js"></script>
    <style>
        body {
            font-family: Arial, sans-serif;
            max-width: 600px;
            margin: 0 auto;
            padding: 20px;
            text-align: center;
        }
        button {
            background-color: #4CAF50;
            border: none;
            color: white;
            padding: 15px 32px;
            text-align: center;
            text-decoration: none;
            display: inline-block;
            font-size: 16px;
            margin: 10px;
            cursor: pointer;
            border-radius: 4px;
        }
        .container {
            margin-top: 100px;
            padding: 20px;
            border-radius: 8px;
            box-shadow: 0 4px 8px rgba(0,0,0,0.1);
        }
    </style>
</head>
<body>
    <div class="container">
        <h1>Solid Login Demo</h1>
        <p>Click the button below to log in with your Solid identity provider</p>
        <button id="loginButton">Login with Solid</button>
        <button id="navigateButton">Go to Welcome Page</button>
        <button id="logoutButton">Logout</button>
    </div>

    <script>
        // Initialize the session
        let session;

        document.addEventListener('DOMContentLoaded', async () => {
            // Import the Session class from the library
            const module = await import('https://unpkg.com/@uvdsl/solid-oidc-client-browser@0.1.3/dist/esm/index.min.js');
            const Session = module.Session;
            
            // Create a new session
            session = new Session();
            
            // Set up the login button
            document.getElementById('loginButton').addEventListener('click', () => {
                // Use a default IDP or let user specify one
                const idp = "https://solidcommunity.net"; // Default IDP - you can change this
                const redirect_uri = window.location.href;
                
                // Redirect to login
                session.login(idp, redirect_uri);
            });

              // Set up the logout button
              document.getElementById('logoutButton').addEventListener('click', () => {
                session.logout();
                alert("Logout! \nWebID: " + session.webId);
            });
            
            // Set up the navigation button
            document.getElementById('navigateButton').addEventListener('click', () => {
                // Navigate to the welcome page
                window.location.href = 'welcome.html';
            });
            
            // Handle redirect after login
            try {
                // either: handle redirect after login
                await session.handleRedirectFromLogin();
                // or: try to restore the session
                await session.restore();
                if (session.webId) {
                    console.log("Logged in successfully:", session.webId);
                    alert("Login successful! \nWebID: " + session.webId);
                }
            } catch (error) {
                console.error("Error handling login redirect:", error);
            }
        });
    </script>
</body>
</html>

welcome.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Welcome Page</title>
    <script type="module" src="https://unpkg.com/@uvdsl/solid-oidc-client-browser@0.1.3/dist/esm/index.min.js"></script>
    <style>
        body {
            font-family: Arial, sans-serif;
            max-width: 600px;
            margin: 0 auto;
            padding: 20px;
            text-align: center;
        }
        .container {
            margin-top: 100px;
            padding: 20px;
            border-radius: 8px;
            box-shadow: 0 4px 8px rgba(0,0,0,0.1);
        }
        .user-info {
            margin-top: 20px;
            padding: 10px;
            background-color: #f8f9fa;
            border-radius: 4px;
            text-align: left;
        }
        button {
            background-color: #4CAF50;
            border: none;
            color: white;
            padding: 10px 20px;
            text-align: center;
            text-decoration: none;
            display: inline-block;
            font-size: 16px;
            margin: 10px;
            cursor: pointer;
            border-radius: 4px;
        }
    </style>
</head>
<body>
    <div class="container">
        <h1>Hello!</h1>
        <div id="welcome-message">Welcome to the application</div>
        <div id="user-info" class="user-info">
            <p>WebID: <span id="webid">Not logged in</span></p>
        </div>
        <button id="back-button">Back to Login Page</button>
    </div>

    <script>
        document.addEventListener('DOMContentLoaded', async () => {
            // Import the Session class from the library
            const module = await import('https://unpkg.com/@uvdsl/solid-oidc-client-browser@0.1.3/dist/esm/index.min.js');
            const Session = module.Session;
            
            // Create a new session
            const session = new Session();
            
            // Try to restore the session
            try {
                // either: handle redirect after login
                await session.handleRedirectFromLogin();
                // or: try to restore the session
                await session.restore();
                
                // Update the UI
                if (session.webId) {
                    document.getElementById('webid').textContent = session.webId;
                    document.getElementById('welcome-message').textContent = 
                        `Welcome! You are logged in.`;
                } else {
                    document.getElementById('welcome-message').textContent = 
                        "You're not logged in. Please return to the login page.";
                }
            } catch (error) {
                console.error("Error restoring session:", error);
                document.getElementById('welcome-message').textContent = 
                    "Error restoring session. Please try logging in again.";
            }
            
            // Set up the back button
            document.getElementById('back-button').addEventListener('click', () => {
                window.location.href = 'index.html';
            });
        });
    </script>
</body>
</html>

Clone this wiki locally