Skip to content

Commit

Permalink
Merge pull request #21 from DIMO-Network/moiz/auth-state
Browse files Browse the repository at this point in the history
Persistent Auth State
  • Loading branch information
MoizAhmedd authored Nov 21, 2024
2 parents 2b97926 + 658d53d commit df57eba
Show file tree
Hide file tree
Showing 11 changed files with 215 additions and 69 deletions.
Binary file not shown.
Binary file not shown.
26 changes: 13 additions & 13 deletions example-dimo-auth/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion example-dimo-auth/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
"@types/node": "^16.18.114",
"@types/react": "^18.3.11",
"@types/react-dom": "^18.3.1",
"@dimo-network/login-with-dimo": "file:./dimo-network-login-with-dimo-0.0.5.tgz",
"@dimo-network/login-with-dimo": "file:./dimo-network-login-with-dimo-0.0.7.tgz",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-scripts": "5.0.1",
Expand Down
31 changes: 18 additions & 13 deletions example-dimo-auth/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,12 @@ import {
LoginWithDimo,
ShareVehiclesWithDimo,
initializeDimoSDK,
useDimoAuthState,
} from "@dimo-network/login-with-dimo";

function App() {
const [permissionsEnabled, setPermissionsEnabled] = useState(false);
const { isAuthenticated } = useDimoAuthState();

// Toggle handler
const handleToggle = () => {
Expand Down Expand Up @@ -43,20 +45,23 @@ function App() {

<div>
<h3>Popup Example</h3>
<LoginWithDimo
mode="popup"
onSuccess={(authData) => console.log("Success:", authData)}
onError={(error) => console.error("Error:", error)}
permissionTemplateId={permissionsEnabled ? "1" : undefined}
// vehicles={["585","586"]}
/>

<ShareVehiclesWithDimo
mode="popup"
onSuccess={(authData) => console.log("Success:", authData)}
onError={(error) => console.error("Error:", error)}
permissionTemplateId={"1"}
/>
{isAuthenticated ? (
<ShareVehiclesWithDimo
mode="popup"
onSuccess={(authData) => console.log("Success:", authData)}
onError={(error) => console.error("Error:", error)}
permissionTemplateId={"1"}
/>
) : (
<LoginWithDimo
mode="popup"
onSuccess={(authData) => console.log("Success:", authData)}
onError={(error) => console.error("Error:", error)}
permissionTemplateId={permissionsEnabled ? "1" : undefined}
// vehicles={["585","586"]}
/>
)}
</div>

<div>
Expand Down
17 changes: 10 additions & 7 deletions example-dimo-auth/src/index.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
import React from "react";
import ReactDOM from "react-dom/client";
import "./index.css";
import App from "./App";
import reportWebVitals from "./reportWebVitals";
import { DimoAuthProvider } from "@dimo-network/login-with-dimo";

const root = ReactDOM.createRoot(
document.getElementById('root') as HTMLElement
document.getElementById("root") as HTMLElement
);
root.render(
<React.StrictMode>
<App />
<DimoAuthProvider>
<App />
</DimoAuthProvider>
</React.StrictMode>
);

Expand Down
71 changes: 71 additions & 0 deletions sdk/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,33 @@ import {
});
```

### The Dimo Auth Provider

The Dimo Auth Provider is used to get the auth state value from the SDK

Any components that require this value should be wrapped in the DimoAuthProvider, as follows

```
<DimoAuthProvider>
<SomeComponentThatNeedsDimoState/>
</DimoAuthProvider/>
```

Now, in the component the auth state can be fetched as follows

```
import {,
useDimoAuthState,
} from "@dimo-network/login-with-dimo";
const { isAuthenticated } = useDimoAuthState();
```

Based on this authenticated state, you can render the necessary Dimo components

### Using the Button Components

The following example shows both buttons being rendered, with no auth state checking
```
import {
LoginWithDimo,
Expand All @@ -58,4 +83,50 @@ import {
// Optionally, specify vehicles (uncomment the line below to use it)
// vehicles={["585","586"]} // Specify the vehicles to be accessed when triggered
/>
```

### Putting it all together

In many cases - developers may want to couple/decouple usage of these components

A common flow is
1. Show the login button, when in authenticated
2. Show the Share Vehicles button, when authenticed

This can be achieved by simply wrapping those buttons in a conditional as follows, to create a full example as follows

```
import {
LoginWithDimo,
ShareVehiclesWithDimo,
initializeDimoSDK,
useDimoAuthState,
} from "@dimo-network/login-with-dimo";
const { isAuthenticated } = useDimoAuthState();
initializeDimoSDK({
clientId: process.env.REACT_APP_DIMO_CLIENT_ID!,
redirectUri: process.env.REACT_APP_DIMO_REDIRECT_URI!,
});
...
{isAuthenticated ? (
<ShareVehiclesWithDimo
mode="popup"
onSuccess={(authData) => console.log("Success:", authData)}
onError={(error) => console.error("Error:", error)}
permissionTemplateId={"1"}
/>
) : (
<LoginWithDimo
mode="popup"
onSuccess={(authData) => console.log("Success:", authData)}
onError={(error) => console.error("Error:", error)}
permissionTemplateId={permissionsEnabled ? "1" : undefined}
// vehicles={["585","586"]}
/>
)}
```
2 changes: 1 addition & 1 deletion sdk/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@dimo-network/login-with-dimo",
"version": "0.0.6",
"version": "0.0.7",
"description": "",
"main": "dist/index.js",
"types": "dist/index.d.ts",
Expand Down
66 changes: 66 additions & 0 deletions sdk/src/auth/context/DimoAuthContext.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
// DimoAuthContext.tsx
import React, { createContext, useContext, useEffect, useState } from "react";
import { getJWTFromCookies } from "../../storage/storageManager";
import { isTokenExpired } from "../../token/tokenManager";

// Define the type of the context
type DimoAuthContextType = {
isAuthenticated: boolean; // Read-only for app developers
};

// Create the context
const DimoAuthContext = createContext<DimoAuthContextType | undefined>(
undefined
);

// Internal updater function type (hidden from the app)
type DimoAuthUpdaterContextType = {
setAuthenticated: React.Dispatch<React.SetStateAction<boolean>>;
};
const DimoAuthUpdaterContext = createContext<
DimoAuthUpdaterContextType | undefined
>(undefined);

// Provider to manage auth state
export const DimoAuthProvider = ({
children,
}: {
children: React.ReactNode;
}) => {
const [isAuthenticated, setAuthenticated] = useState(false);

useEffect(() => {
const jwt = getJWTFromCookies();
if (jwt && !isTokenExpired(jwt)) {
setAuthenticated(true);
}
}, []);

return (
<DimoAuthContext.Provider value={{ isAuthenticated }}>
<DimoAuthUpdaterContext.Provider value={{ setAuthenticated }}>
{children}
</DimoAuthUpdaterContext.Provider>
</DimoAuthContext.Provider>
);
};

// Hook to expose read-only auth state to developers
export const useDimoAuthState = () => {
const context = useContext(DimoAuthContext);
if (!context) {
throw new Error("useDimoAuthState must be used within a DimoAuthProvider");
}
return context; // Only exposes isAuthenticated
};

// Internal SDK hook to update the state
export const useDimoAuthUpdater = () => {
const context = useContext(DimoAuthUpdaterContext);
if (!context) {
throw new Error(
"useDimoAuthUpdater must be used within a DimoAuthProvider"
);
}
return context; // Exposes setAuthenticated only for SDK
};
Loading

0 comments on commit df57eba

Please sign in to comment.