npm package: @jaaahn/hyper-id-client
Description: For internal use only.
Author: Jaaahn
Latest version: 1.0.0-beta.17

# HyperID Client Library

**This library is for internal use only.**

## Client

### Initialize Auth instance

```js
// auth.js

import { clientInstance } from "@jaaahn/hyper-id-client";

// Create new auth instance
let auth = new clientInstance({
    apiURL: "https://localhost:8080",
    webURL: "https://localhost:3000",
    publicKey: "your_app_public_key",
    includeTokenIn: ["list_of_baseURLs_to_your_first_party_server"],
});

// Add axios interceptors to inject access token in requests (if using axios)
import axios from "axios";
auth.addAxiosInterceptors(axios);

// Mount library on Vue
import router from "./router.js";
auth.installVue(router);

// Catch user updates
let removeUserListener = auth.addEventListener("userChanged", (user) => {
    console.log("user changed", user);

    // DEPRECATION NOTICE: This object includes an `app_data` key. Please use the readAppData() function as the userChanged event won't fire if appData is changed
});

// Catch auth status updates
let removeStatusListener = auth.addEventListener("statusChanged", (status) => {
    console.log("status changed", status);

    // Status syntax
    // {
    //     systemStatus: String; // "initializing" or "loggedOut" or "loggedIn"
    // }
});

let removeRefreshStartedListener = auth.addEventListener("refreshStarted", () => {
    console.log("refresh of token has been triggered");
});

let removeTokenChangedListener = auth.addEventListener("tokenChanged", (token) => {
    console.log("token set", token),

    // NOTE: Use with caution! Nobody should ever get their hands on this token!
})

// Start HyperID
auth.startInitialization();

// Make the instance available to the rest of your application
export default auth;

// Code to remove listeners, if no longer they're needed
/* removeUserListener();
removeStatusListener(); */
```

### Working with Apollo Client

```js
// apollo.js

import { ApolloClient, InMemoryCache, HttpLink } from "@apollo/client/core";
import auth from "./auth.js";

// Create a custom http link
export const apolloHttpLink = new HttpLink({
    uri: "https://localhost:8085/graphql",
});

// HyperID will create a custom ApolloLink and append the provided HttpLink to it
// Will return a link chain of both the HttpLink and HyperID's link
const link = auth.addApolloInterceptors(apolloHttpLink);

// Create ApolloClient
export default new ApolloClient({
    cache: new InMemoryCache(),
    link: link, // With out custom Link chain
});
```

### Open login page

```js
auth.authenticate();
```

Optional: Provide a route that is opened after login:

```js
auth.authenticate("/my_profile");
```

### Open HyperID account settings page

```js
auth.openAccountSettings();
```

### Logout

```js
await auth.logout();
```

### Refresh token if required

Only use this function if building your own request interceptor or token management system.
For usage with axios, socket.io and apollo client, we recommend using the provided request interceptors that handle refreshing the token for you.

```js
await auth.startInitialization();
```

### Get token expiration date

```js
let exp = auth.getTokenExpirationDate();
```

### Get token

```js
let token = auth.getToken();
// USE WITH CAUTION! Tokens should never be exposed or made known to anybody!
```

### Get refresh token

```js
let token = auth.getRefreshToken();
// USE WITH CAUTION! Tokens should never be exposed or made known to anybody!
```

### Get user info (also triggers userChanged event)

```js
await auth.getUser();
```

DEPRECATION NOTICE: This object includes an `app_data` key. Please use the readAppData() function as the userChanged event won't fire if appData is changed

### Read user's AppData

```js
await auth.readAppData();
```

### Write user's AppData

```js
await auth.writeAppData(data);
```

The data object should be a dictionary containing key-value pairs.  
Only strings can be stored as values. Any non-ASCII characters are automatically removed from keys.  
If a key is set to `null`, it will be deleted from the DB.
If an existing key is not mentioned, it won't be touched.  
Example:

```js
{
    hello: "world",
    foo: 2, // Will be transformed to string
    bar: true, // Will be transformed to string
    test: null, // Will delete the key `test` from the DB
}
```

**Warning:** This does NOT perform escaping so make shure to have a XSS preventioning system implemented if storing user generated content

## Server

### Initialization

```js
// auth.js

import { serverInstance } from "@jaaahn/hyper-id-client";

// Create new auth server instance
let auth = new serverInstance({
    apiURL: "https://localhost:8080",
    privateKey: "your_app_private_key",
});

export default auth;
```

### Express verify session middleware

```js
// Add the middleware to your routes
// It is important that you call the `auth.express.verifySession` function!

// A valid session is required
app.get("/myRoute", auth.express.verifySession(), (request, response) => {
    let { user, appdata } = request.hyperid;
});

// A valid session is NOT required; the user info will still be available if a user is logged in
app.get("/myRoute", auth.express.verifySession(false), (request, response) => {
    let { user, appdata } = request.hyperid;
});
```

### Apollo verify session (using express server as a base)

Validating a session

```js
// index.js

app.use(
    "/graphql",
    expressMiddleware(server, {
        context: async ({ req, res }) => {
            /**
             * Function parses request, validates a present session and returns the user and appdata
             * Will return { user: null, appdata: null } if a user is not logged in
             */
            let { user, appdata } = await auth.apollo.validateSession(req);

            return { user, appdata, req, res };
        },
    })
);
```

Enforcing a session

```js
// resolvers.js

Query: {
    async posts(_, args, contextValue) {
        let user = contextValue.user;
        let appdata = contextValue.appdata;

        /**
         * Will throw a GraphQLError if no user is logged in
         */
        auth.apollo.enforceSession(contextValue);

        // Any code to resolve the "posts" query
    },
},
```

### Read user's AppData

```js
await auth.readAppData(user_id);
```

### Write user's AppData

```js
await auth.writeAppData(user_id, data);
```

The data object should be a dictionary containing key-value pairs.  
Only strings can be stored as values. Any non-ASCII characters are automatically removed from keys.  
If a key is set to `null`, it will be deleted from the DB.
If an existing key is not mentioned, it won't be touched.  
Example:

```js
{
    hello: "world",
    foo: 2, // Will be transformed to string
    bar: true, // Will be transformed to string
    test: null, // Will delete the key `test` from the DB
}
```

**Warning:** This does NOT perform escaping so make shure to have a XSS preventioning system implemented if storing user generated content

### Get info about app

```js
await auth.getAppInfo();
```

### Get a list of all users

```js
await auth.getAllUsers();
```

### Get one user

```js
await auth.getOneUser(search);
```

Search by user_id or by email.

## Known issues

### "ReferenceError: Cannot access uninitialized variable" in a Vue client with Vue Router

If this error message pops up on your client, try importing your auth instance at the top of `main.js` (at least before importing your router).  
You may use this line: `import auth from "./auth.js"`