Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 36 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,38 @@ import { Graphistry } from '@graphistry/client-api-react';` // + variants for di

See [@graphistry/client-api-react project](projects/client-api-react/README.md), [interactive storybook docs](https://graphistry.github.io/graphistry-js/), and [Create React App project sample](projects/cra-test/README.md)

### Authentication with Client API

For secure authentication, create a `Client` instance and pass it to your components:

```javascript
import { Client, Dataset, EdgeFile, NodeFile } from '@graphistry/client-api';
import { Graphistry } from '@graphistry/client-api-react';

// Create authenticated client
const client = new Client(
'my_username',
'my_password',
'', // org (optional)
'https', // protocol
'hub.graphistry.com' // host
);

// Use with React component
return (
<Graphistry
client={client}
dataset="Miserables"
// other props...
/>
);
```

This approach provides:
- JWT-based authentication (vs deprecated API keys)
- Automatic token management and refresh
- Secure server-to-server communication

<br><br>

## @graphistry/node-api
Expand Down Expand Up @@ -140,9 +172,11 @@ To support server-acceleration and fast interactions, Graphistry decouples uploa

- You can configure your Graphistry server to run as http, https, or both
- Uploads require authentication
- **Recommended**: The `Client` class provides modern JWT-based authentication for both browser and Node.js environments
- The `node-api` client already uses the new JWT-based protocol ("API 3")
- Deprecated: The clientside JavaScript convenience APIs still use the deprecrated "API 1" protocol (key-based), which lacks JWT-based authentication and authorization
- **Deprecated**: The clientside JavaScript convenience APIs still use the deprecated "API 1" protocol (key-based), which lacks JWT-based authentication and authorization
- We recommend clients instead use `fetch` or other HTTP callers to directly invoke the REST API: See how the `node-api` performs it
- The client JavaScript APIs will updated to the new JWT method alongside recent CORS and SSO updates; contact staff if you desire assistance
- **Deprecated**: Legacy API key authentication is still supported but will be phased out
- Sessions are based on unguessable web keys: sharing a secret ID means sharing read access
- Datasets are immutable and thus their integrity is safe for sharing, while session state (e.g., filters) are writable: share a copy when in doubt
- Datasets are immutable and thus their integrity is safe for sharing, while session state (e.g., filters) are writable: share a copy when in doubt
37 changes: 32 additions & 5 deletions projects/client-api-react/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,8 @@ const propTypes = {
onLabelsUpdate: PropTypes.func,
selectionUpdateOptions: PropTypes.object,

queryParamExtra: PropTypes.object
queryParamExtra: PropTypes.object,
client: PropTypes.object
};

const defaultProps = {
Expand Down Expand Up @@ -365,7 +366,8 @@ function generateIframeRef({
url, dataset, props,
axesMap,
iframeStyle, iframeClassName, iframeProps, allowFullScreen,
tolerateLoadErrors
tolerateLoadErrors,
authToken
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

move this out of generateiframeref if possible

}) {

console.debug('@generateIframeRef', { url, dataset, props, axesMap, iframeStyle, iframeClassName, iframeProps, allowFullScreen, tolerateLoadErrors });
Expand Down Expand Up @@ -416,6 +418,26 @@ function generateIframeRef({
),
tap((g) => {
console.debug('new iframe all init updates handled, if any', g);

// store JWT token for iframe auth
if (authToken && client.authTokenValid()) {
try {
localStorage.setItem('graphistry_auth_token', authToken);
console.info('Stored JWT token for iframe authentication');

if (iframe && iframe.contentWindow) {
const targetOrigin = new URL(props.graphistryHost).origin;
iframe.contentWindow.postMessage({
type: 'auth-token-available',
agent: 'graphistryjs',
token: authToken
}, targetOrigin);
}
} catch (error) {
console.warn('Failed to store auth token:', error);
}
}

setFirstRun(false);
if (props.onClientAPIConnected) {
console.debug('has onClientAPIConnected(), calling', props.onClientAPIConnected);
Expand Down Expand Up @@ -465,13 +487,16 @@ const Graphistry = forwardRef((props, ref) => {
onUpdateObservableG,
onSelectionUpdate,
onLabelsUpdate,
selectionUpdateOptions
selectionUpdateOptions,
client
} = props;

const [loading, setLoading] = useState(!!props.loading);
const [dataset, setDataset] = useState(props.dataset);
const [loadingMessage, setLoadingMessage] = useState(props.loadingMessage || '');

const authToken = props.client && props.client.authTokenValid() ? props.client._token : null;

const [g, setG] = useState(null);
const [gObs, setGObs] = useState(null);
const [gSub, setGSub] = useState(null);
Expand Down Expand Up @@ -523,9 +548,10 @@ const Graphistry = forwardRef((props, ref) => {

return {
g,
client,
...exportedCalls
};
}, [g]);
}, [g, client, dataset]);

useEffect(() => {
if (g && onSelectionUpdate) {
Expand Down Expand Up @@ -583,7 +609,8 @@ const Graphistry = forwardRef((props, ref) => {
url, dataset, props,
axesMap,
iframeStyle, iframeClassName, iframeProps, allowFullScreen,
tolerateLoadErrors
tolerateLoadErrors,
authToken
});

const children = [
Expand Down