Skip to content

Commit

Permalink
feat: add useFetch to default credentials
Browse files Browse the repository at this point in the history
  • Loading branch information
jrea committed Oct 19, 2022
1 parent 5245ad5 commit 2902dbd
Show file tree
Hide file tree
Showing 4 changed files with 128 additions and 0 deletions.
4 changes: 4 additions & 0 deletions packages/react/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,10 @@ function App() {
}
```
## useFetch
When using Nile with multiple webservers, you can piggyback off of Nile to enforce access to your own backend. See the [useFetch](./src/lib/hooks/useFetch/README.md) documetation for more information
## Available components
[EntityForm](./src/components/EntityForm/README.md)
Expand Down
1 change: 1 addition & 0 deletions packages/react/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ export { NileProvider, useNile } from './context';
export { default as Queries } from './lib/queries';

export { useInstances } from './lib/hooks/useInstances';
export { default as useFetch } from './lib/hooks/useFetch';

export { AttributeType, Attribute } from './lib/SimpleForm/types';

Expand Down
114 changes: 114 additions & 0 deletions packages/react/src/lib/hooks/useFetch/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
## useFetch

This hook can be used on conjunction with other backend services configured to work with Nile. All it does is ensure `credentials` are set to `include` to be sure cookies HTTP-only cookies are passed to the secondary service.

### Usage

```typescript
import { Stack, Button } from '@mui/joy';
import { useNile, useFetch } from '@thenile.dev/react';

function CustomComponent() {
const nile = useNile();
const fetch = useFetch();

const fetchFromBackend = React.useCallback(() => {
async function doRequest() {
try {
const myResult = await fetch('https://my.backend.service');
console.log(myResult);
} catch (e) {
console.error(e.message);
}
}
doRequest();
}, []);

const fetchFromNile = React.useCallback(() => {
async function doRequest() {
try {
const myResult = await nile.users.listUsers();
console.log(myResult);
} catch (e) {
console.error(e.message);
}
}
doRequest();
}, []);

return (
<Stack>
<Button onClick={fetchFromNile}>Do Request from Nile</Button>;
<Button onClick={fetchFromBackend}>Do Request from backend</Button>;
</Stack>
);
}
```

## Handling CORS

In order for `useFetch` and `useNile` to work well together, the secondary web server needs set up to handle CORS. This allows for cookies to be shared transparently between your domain and Nile. Below is an example (in nextjs) for using Nile as the source of truth for authentication on a secondary server:

```typescript
import type { NextApiRequest, NextApiResponse } from 'next';
import Cors from 'cors';
import Nile from '@theniledev/js';

// Initialize Nile
const nile = Nile({
basePath: 'https://prod.thenile.dev',
workspace: 'myWorkspace',
});

// Initializing the cors middleware
// You can read more about the available options here: https://github.com/expressjs/cors#configuration-options
const cors = Cors({
origin: ['https://mysupercoolsite.com'], // **important** the `origin` here needs to match the `origin` CORS header on `https://prod.thenile.dev`
methods: ['POST', 'GET', 'HEAD'],
credentials: true, // be sure to accept credentials passed by the HTTP-only cookie
});

// Helper method to wait for a middleware to execute before continuing
// And to throw an error when an error happens in a middleware
function runMiddleware(
req: NextApiRequest,
res: NextApiResponse,
fn: Function
) {
return new Promise((resolve, reject) => {
fn(req, res, (result: any) => {
if (result instanceof Error) {
return reject(result);
}

return resolve(result);
});
});
}

export default async function handler(
req: NextApiRequest,
res: NextApiResponse
) {
// Run the middleware
await runMiddleware(req, res, cors);
const { token } = req.cookies;

if (typeof token === 'string') {
try {
const valid = await nile.developers.validateDeveloper({
token: { token },
});
// nile.authToken = token; // use the valid token on the server's client to make requests to nile, if necessary
console.log(valid); // undefined means the developer is valid
// request for policies you would like to enforce
} catch (e) {
console.log(e.message);
// developer does not have permission to the workspace
res.status(403).send();
}
}
// Rest of the API logic
res.json({ message: 'Hello Everyone!' });
}
```
9 changes: 9 additions & 0 deletions packages/react/src/lib/hooks/useFetch/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
/**
* A wrapper function for `fetch`, to be sure credentials are included in the request
* This is necessary for a client requestion from 2 or more backend services
* @returns A promise
*/
export default function useFetch() {
return (input: RequestInfo | string, init?: RequestInit): Promise<Response> =>
fetch(input, { ...init, credentials: 'include' });
}

0 comments on commit 2902dbd

Please sign in to comment.