npm promotes metadefinitions

    @inrupt/solid-auth-fetcher
    TypeScript icon, indicating that this package has built-in type declarations

    0.0.6 • Public • Published

    Solid Auth Fetcher

    A client tool to login and make authenticated requests to Solid compliant servers.

    NOTE: The interface documented here is the proposed interface not the one actually implemented yet. For the actually implemented interface see the "Example Usage"

    Installation

    npm install solid-auth-fetcher

    Examples Usage

    Setting up the examples

    git clone https://github.com/inrupt/solid-auth-fetcher.git
    cd solid-auth-fetcher
    npm i
    npm run bootstrap-examples
    # Run each example
    npm run dev-bundle
    npm run dev-script
    npm run dev-server
    npm run dev-ios
    npm run dev-android

    At this point, a test application will be running on port 3001 and a test solid server will be running on port 9001

    Importing

    In the browser via the script tag:

    <script src="/path/to/solidAuthFetcher.bundle.js"></script>
    </script>
        solidAuthFetcher.getSession().then((session) => {
            if (!session.loggedIn) {
                console.log("User is not logged in")
            } else {
                console.log("User is logged in")
            }
        })
    </script>

    Using import

    import { getSession } from "solid-auth-fetcher"
    
    getSession().then((session) => {
        if (!session.loggedIn) {
            console.log("User is not logged in")
        } else {
            console.log("User is logged in")
        }
    })

    Using require

    const solidAuthFetcher = require("solid-auth-fetcher")
    
    solidAuthFetcher.getSession().then((session) => {
        if (!session.loggedIn) {
            console.log("User is not logged in")
        } else {
            console.log("User is logged in")
        }
    })

    For Use in the Web Browser

    Simple Login

    Let's first see how we can initiate a login.

    import { login, getSession } from 'solid-auth-fetcher'
    
    // getSession will return a session object
    getSession().then(async (session) => {
      if (!session) {
        const session = await login({
          // You could provide either a "webId" field, or an "oidcIssuer" field if
          // you know who the user's OIDC issuer is. If neither are provided, a
          // pop-up will ask the user to provide one. If it is running on the server
          // the popup parameter will be ingored.
          oidcIssuer: 'https://identityProvider.com', 
    
          // Note that when 'popUp' is false, the browser will redirect the
          // current page thus stopping the current flow (default is false).
          popUp: false,
          
          // The page that that should be queried once login is complete
          redirectUrl: 'https://mysite.com/redirect',
        })
        // Chances are that this session will not be logged in. Instead, your browser
        // window will be redirected and you'll be able to get the logged in session
        // via `getSession` or `onSession` after the redirect.
        console.log(session);
      }
    })

    Login with a PopUp Window

    By default, the user is redirected to the login page within the same window, but you might want to maintain the state of your application without it being interrupted by a redirect. To do so, you can use a popup. If you do want to use a popup, you should provide a popUpRedirectPath for the popup window to redirect to. At this path you should run the handlePopUpRedirect function

    index.html:

    <html>
    <head>
    <script src="/path/to/solidAuthFetcher.bundle.js"></script>
    <script>
      function login() {
        solidAuthFetcher.login({
          oidcIssuer: "https://identityProvider.com",
          popUp: true,
          popUpRedirectPath: "/popup.html"
        })
      }
    </script>
    <head>
    
    <body>
      <button onClick="login()">login</button>
    </body>
    </html>

    popup.html:

    <html>
    <head>
    <script src="/path/to/solidAuthFetcher.bundle.js"></script>
    <script>
      solidAuthFetcher.handlePopUpRedirect()
    </script>
    <head>
    </html>

    Getting alerted on a new session

    Using getSession() to determine if a user is logged in is fine, but it's generally better to be alerted when a user has logged in. For this, you can use onSession(). Then you can use that user to fetch.

    import { onSession } from 'solid-auth-fetcher'
    
    onSession((session) => {
      if (session.loggedIn) {
        console.log(user.webId)
        session.fetch('https://example.com/resource')
      }
    })

    Fetching without the Session Object

    It is also possible to fetch without the "session" object. Keep in mind that doing so will not make an authenticated fetch if a user is not logged in.

    import { fetch } from 'solid-auth-fetcher'
    
    fetch('https://example.com/resource', {
      method: 'post',
      body: 'What a cool string!'
    }).then(async (response) => {
      console.log(await response.text());
    })

    Logging in Multiple Users

    There may be some cases where you want to manage multiple users logged in at once. For this we can use the uniqueLogin function.

    import { uniqueLogin, getSessions } from 'solid-auth-fetcher'
    
    const myWebId = 'https://example.com/profile/card#me'
    getSessions().then((sessions) => {
      // If my WebID hasn't been logged in yet.
      if (sessions.some((session) => session.webId === myWebId)) {
        await uniqueLogin({
          webId: myWebId,
          redirectUrl: "https://myapp.com/redirect"
        })
      }
    })

    Custom Storage

    By default, Solid-Auth-Fetcher will use your browser's local storage. But, you may want to use your own implementation. To do so, you can use the getCustomAuthFetcher method and provide its own storage.

    import { getCustomAuthFetcher } from 'solid-auth-fetcher'
    
    getCustomAuthFetcher({
      storage: {
        // Key is a string and a Promise<string> should be returned
        get: (key) => {/* perform get */}
        // Key and value are both strings and a Promise<void> should be returned
        set: (key, value) => {/* perform set */}
        // Key is a string and a Promise<void> should be returned
        delete: (key) => {/* perform delete */}
      }
    }).then((authFetcher) => { /* Do something */ })

    Custom Redirect Handling

    By default, Solid-Auth-Fetcher redirects automatically upon login, and automatically handles a redirect back to the app when it is initialized. But, you may want to handle redirects manually. To do this you can use the doNotAutoRedirect and the doNotAutoHandleRedirect flags along with the handleRedirect method.

    import { getCustomAuthFetcher } from 'solid-auth-fetcher'
    
    // Get the custom auth fetcher that will not trigger `handleRedirect` automatically
    getCustomAuthFetcher({
      doNotAuthHandleRedirect: true
    }).then(async (authFetcher) => {
    
      // If we are at the redirect location we want to handle it
      if (window.location.pathname === "/redirect") {
        // Call the handleRedirect method with the current url
        await authFetcher.handleRedirect(window.location.href);
        // Once the redirect is handled we can return to the home page
        window.history.replaceState({}, "", window.location.origin)
    
    
      // If we are not at the redirect route we should trigger a log in or get
      //  the session
      } else {
        const curSession = await getSession()
        if (curSession.loggedIn) {
          console.log("The user is logged in");
        } else {
          // Log in if the user is not already
          const session = await authFetcher.login({
            oidcIssuer: 'https://identityProvider.com', 
            redirectUrl: 'https://mysite.com/redirect',
            // Notice this flag the suppresses the auto redirect
            doNotAutoRedirect: true
          });
    
          // Because we have suppressed the redirect, the session will not
          // be logged in, but rather have a "NeededAction" object that will
          // describe where we should redirect
          if (
            session.neededAction &&
            session.neededAction.actionType === "redirect"
          ) {
            // Perform the manual redirect
            window.location.href = session.neededAction.redirectUrl
          }
        }
      }
    })

    For Use on the Server

    Unlike on the browser, servers often need to deal with multiple users, so the server API has been configured to deal with that by default:

    import { getCustomAuthFetcher } from "solid-auth-fetcher";
    import express from "express";
    import expressSession from "express-session";
    
    // First we'll initialize an auth fetcher and hook it up to our own stroage
    let authFetcher;
    let authSessions = {}
    getCustomAuthFetcher({
      storage: {
        get: (key) => {/* perform get */}
        set: (key, value) => {/* perform set */}
        delete: (key) => {/* perform delete */}
      }
    }).then(async (af) => { 
      authFetcher = af
      // Initialize any sessions that are already in stroage
      const curAuthSessions = await getSessions()
      curAuthSessions.forEach((curAuthSession) => {
        authSessions[curAuthSession.localUserId] = curAuthSession
      })
     })
    
    const app = express();
    
    app.use(
      expressSession({
        secret: "I let Kevin's son beat me in foosball",
        cookie: { secure: true }
      })
    );
    
    app.post("/login", async (req, res) => {
        const authSession = await uniqueLogin({
            oidcIssuer: req.body.webid,
            redirect: "https://myapp.com/redirect",
            clientId: "coolApp"
        });
        req.session.localUserId = authSession.localUserId;
        authSessions[authSession.localUserId] = authSession;
        if (
            authSession.neededAction &&
            authSession.neededAction.actionType === "redirect"
        ) {
            res.redirect(session.authSession.redirectUrl);
        }
    });
    
    app.get("/redirect", async (req, res) => {
      const authSession = await handleRedirect(req.url);
      if (authSession.loggedIn) {
        req.session.localUserId = authSession.localUserId;
        authSessions[authSession.localUserId] = authSession;
      }
      res.redirect("/fetch");
    });
    
    app.get("/fetch", async (req, res) => {
      if (
        req.session &&
        req.session.localUserId &&
        sessions[req.session.localUserId] &&
        sessions[req.session.localUserId].webId
      ) {
        const result = await authSessions[
          req.session.localUserId
        ].fetch("http://example.com/resource", {});
        res.send(result.text())
      }
    });
    
    app.listen(3000)

    General Usage

    login(options): Session

    Kick off the login process for a global user:

    import { login } from 'solid-auth-fetcher';
    
    
    login({
        // You could provide either a "webId" field, or an "issuer"
        // field if you know who the user's OIDC issuer is. If
        // neither are provided, a pop-up will ask the user to
        // provide one.
        webId: 'https://example.com/profile/card#me', 
    
        // Note that when 'popUp' is false, the browser will
        // redirect the current page thus stopping the current
        // flow (default is false).
        popUp: false,
    
        redirect: 'https://mysite.com/redirect'
    }).then((session) => {})

    Options:

    Field Name Required? Type Description Default
    webId Yes, unless issuer is provided String or URL The user's WebID undefined
    issuer Yes, unless webId is provided String or URL The user's issuer undefined
    redirect Yes String or URL The URI within this application that the user should be redirected to after successful login. This can be either a web URL or a mobile URL scheme undefined
    clientId In the current spec, no, in the upcoming spec, yes String or URL The app's WebID undefined
    popUp No Boolean If true, the login process will initiate via a popup. This only works on web clients. false
    popUpRedirectPath No String The path to which a popup window should redirect after the user is logged in undefined
    state No String The state will be provided with the User's Session object once they have logged in undefined
    doNotAutoRedirect No Boolean If true, the browser will not auto redirect. Note that auto redirect only happens if Solid-Auth-Fetcher is running in the browser false

    uniqueLogin(options): Session

    Kick off the login process for a unique user. This allows you to log in multiple users with solid-auth-fetcher. It's a useful feature for apps that wish to support multiple users being logged into the same client, or for servers that work with multiple clients.

    import { uniqueLogin } from 'solid-auth-fetcher';
    
    uniqueLogin({
        webId: 'https://example.com/profile/card#me',
        popUp: false
        redirect: 'https://mysite.com/redirect'
    }).then((session) => {})

    The options for uniqueLogin() are identical to login().

    fetch(url, options): result

    Send an HTTP request to a Solid Pod as the global user:

    import { fetch } from 'solid-auth-fetcher';
    
    fetch('https://example.com/resource', {
        method: 'POST',
        headers: {
            "Content-Type": "text/plain"
        },
        body: 'Sweet body, bro'
    }).then((result) => {})

    Fetch follows the WHATWG Fetch Standard.

    logout()

    Log the global user out:

    import { logout } from 'solid-auth-fetcher';
    
    logout().then(() => {})

    getSession(): Session

    Retrieve the session for the global user:

    import { getSession } from 'solid-auth-fetcher';
    
    await getSession().then((session) => {})

    getSessions(): Session[]

    Retrieve all sessions currently registered with authFetcher

    import { getSessions } from 'solid-auth-fetcher';
    
    await getSessions().then((sessions) => {})

    onSession(callback)

    Register a callback function to be called when a new session is received after the user has logged in:

    import { onSession } from 'solid-auth-fetcher'
    
    onSession((session) => {
      console.log(session.webId)
    })

    The callback receives a Session object as its sole parameter.

    onLogout(callback)

    Register a callback function to be called when a session is logged out:

    import { onLogout } from 'solid-auth-fetcher'
    
    onLogout((session) => {
      console.log(session.webId)
    })

    onRequest(callback)

    Register a callback function to be called whenever a request is made:

    import { onRequest } from 'solid-auth-fetcher'
    
    onRequest((url, requestOptions) => {
      console.log(url)
    })

    Session

    The session object contains information about the logged in user, as well as functions that can be executed as that user (e.g. logout()).

    interface Session {
      localUserId: String // The id to internally track this session
      loggedIn: Boolean // True if this session is logged in
      webId?: String // The user's WebID.
      state?: String // Any state that was passed upon login.
      neededAction?: {
          actionType: "redirect" | "inaction"
      } // Indicates that you must execute some action to continue.
      logout: () => void // Function to log this user out.
      fetch: (url: string, options: {}): Promise<Result> // Function to fetch as this user
    }

    handleRedirect(url): Session

    Handle redirects as a part of the OIDC process. Servers using solid-auth-fetcher must manually call this method on redirect, but is done automatically on web and mobile.

    import { handleRedirect } from 'solid-auth-fetcher'
    
    handleRedirect(window.location.href).then((session) => {})

    customAuthFetcher

    Create an instance of AuthFetcher with configurable settings:

    import customAuthFetcher from 'solid-auth-fetcher'
    
    const authFetcher = customAuthFetcher({
        // A custom implementation of how auth fetcher should persist its
        // data.
        storage: { 
            get: (key: string) => Promise<any>
            set: (key: string, value: any) => Promise<void>
            delete: (key: string) => Promise<void>
        },
        
        // If true, handleRedirect will automatically be triggered on web
        // and mobile platforms. Default is true. 
        shouldAutoHandleRedirect: boolean 
    })

    AuthFetcher

    The primary object for logging in, and making authenticated fetches:

    interface AuthFetcher {
        login: (options: {}) => Promise<void>
        fetch: (url: string | URL, options: {}) => Promise<Response>
        logout: () => Promise<void>
        getSession: () => Promise<Session>
        getSessions: () => Promise<Session[]>
        uniqueLogin: (options: {}) => Promise<void>
        onSession: (callback: (session: Session) => any) => void
        onLogout: (callback: (session: Session) => any) => void
        handleRedirect:  (url: string | URL) => Promise<void>
    }

    Injecting your custom functionality

    Any part of solid-auth-fetcher can be modified without the need to commit to the source library. All you need to do is build up a dependency injection heirarchy as seen in https://github.com/inrupt/solid-auth-fetcher/blob/refactor/src/dependencies.ts.

    Keywords

    none

    Install

    npm i @inrupt/solid-auth-fetcher

    DownloadsWeekly Downloads

    5

    Version

    0.0.6

    License

    MIT

    Unpacked Size

    241 kB

    Total Files

    220

    Last publish

    Collaborators

    • astrid.vazquez
    • thisismissem
    • timbl
    • rubenverborgh
    • nseydoux
    • ajacksified
    • pmcb55
    • inrupt_ci
    • virginiabalseiro