Authenticated fetch update (#215)
* Remove MANAGE_APPS permission for available permission * Fix missing header in useAuthenticatedFetch and add docs * Update docs/protected-handlers.md Co-authored-by: Krzysztof Wolski <krzysztof.k.wolski@gmail.com> --------- Co-authored-by: Krzysztof Wolski <krzysztof.k.wolski@gmail.com>
This commit is contained in:
parent
dfd632bb14
commit
f7d38dc8d7
5 changed files with 49 additions and 5 deletions
5
.changeset/happy-insects-talk.md
Normal file
5
.changeset/happy-insects-talk.md
Normal file
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
"@saleor/app-sdk": minor
|
||||
---
|
||||
|
||||
Added useAuthenticatedFetch hook with can construct decorated window.fetch with pre-defined headers with required AppBridge state. Can be used with createProtectedHandler
|
5
.changeset/tall-birds-sort.md
Normal file
5
.changeset/tall-birds-sort.md
Normal file
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
"@saleor/app-sdk": patch
|
||||
---
|
||||
|
||||
Remove MANAGE_APPS from possible permissions, because App should not have it. Mutations that requires MANAGE_APPS will not work with App Token even if permission is set
|
|
@ -24,6 +24,7 @@ export type ProtectedHandlerContext = {
|
|||
- the API URL has been registered, with help of the APL
|
||||
- the request has `authorization-bearer`
|
||||
- the auth token is a valid JWT token created by the Saleor running on the given URL
|
||||
- user has required permissions in the token
|
||||
|
||||
For example purposes our endpoint will only log welcome message:
|
||||
|
||||
|
@ -44,8 +45,10 @@ export const handler = async (
|
|||
/**
|
||||
* If any of the requirements is failed, an error response will be returned.
|
||||
* Otherwise, provided handler function fill be called.
|
||||
*
|
||||
* Last argument is optional array of permissions that will be checked. If user doesn't have them, will return 401 before handler is called
|
||||
*/
|
||||
export default createProtectedHandler(handler, saleorApp.apl);
|
||||
export default createProtectedHandler(handler, saleorApp.apl, ["MANAGE_ORDERS"]);
|
||||
```
|
||||
|
||||
To make your requests successfully communicate with the backend, `saleor-api-url` and `authorization-bearer` headers are required:
|
||||
|
@ -65,3 +68,30 @@ fetch("/api/protected", {
|
|||
```
|
||||
|
||||
If you want to read more about `appBridgeState`, check [App Bridge](./app-bridge.md) documentation.
|
||||
|
||||
### Using `useAuthenticatedFetch()` hook
|
||||
|
||||
Instead of manually attaching headers with AppBridge context, you can use `useAuthenticatedFetch()` hook
|
||||
|
||||
Since it requires AppBridge, it's only available in browser context. It depends on `Window` object,
|
||||
so your app will break if Next.js tries to render it server-side. Hence, ensure component that uses the hook is imported with dynamic()
|
||||
|
||||
Component must be within `AppBridgeProvider` to have access to the AppBridge
|
||||
|
||||
```tsx
|
||||
import { useAuthenticatedFetch } from "@saleor/app-sdk/app-bridge";
|
||||
import { useEffect } from "react";
|
||||
|
||||
export const ClientComponent = () => {
|
||||
const fetch = useAuthenticatedFetch();
|
||||
|
||||
useEffect(() => {
|
||||
/**
|
||||
* Auth headers are set up automatically, so you can just call the fetch function
|
||||
*/
|
||||
fetch("/api/protected");
|
||||
}, [fetch]);
|
||||
|
||||
return <div>Your UI</div>;
|
||||
};
|
||||
```
|
||||
|
|
|
@ -1,4 +1,8 @@
|
|||
import { SALEOR_AUTHORIZATION_BEARER_HEADER, SALEOR_DOMAIN_HEADER } from "../const";
|
||||
import {
|
||||
SALEOR_API_URL_HEADER,
|
||||
SALEOR_AUTHORIZATION_BEARER_HEADER,
|
||||
SALEOR_DOMAIN_HEADER,
|
||||
} from "../const";
|
||||
import { AppBridge } from "./app-bridge";
|
||||
import { useAppBridge } from "./app-bridge-provider";
|
||||
|
||||
|
@ -10,11 +14,12 @@ type HasAppBridgeState = Pick<AppBridge, "getState">;
|
|||
export const createAuthenticatedFetch =
|
||||
(appBridge: HasAppBridgeState, fetch = global.fetch): typeof global.fetch =>
|
||||
(input, init) => {
|
||||
const { token, domain } = appBridge.getState();
|
||||
const { token, domain, saleorApiUrl } = appBridge.getState();
|
||||
|
||||
const headers = new Headers(init?.headers);
|
||||
headers.set(SALEOR_DOMAIN_HEADER, domain);
|
||||
headers.set(SALEOR_AUTHORIZATION_BEARER_HEADER, token ?? "");
|
||||
headers.set(SALEOR_API_URL_HEADER, saleorApiUrl ?? "");
|
||||
|
||||
const clonedInit: RequestInit = {
|
||||
...(init ?? {}),
|
||||
|
@ -27,7 +32,7 @@ export const createAuthenticatedFetch =
|
|||
/**
|
||||
* Hook working only in browser context. Ensure parent component is dynamic() and mounted in the browser.
|
||||
*/
|
||||
export const useAuthenticatedFetch = (fetch = global.fetch) => {
|
||||
export const useAuthenticatedFetch = (fetch = window.fetch): typeof window.fetch => {
|
||||
const { appBridge } = useAppBridge();
|
||||
|
||||
if (!appBridge) {
|
||||
|
|
|
@ -22,7 +22,6 @@ export type Permission =
|
|||
| "MANAGE_USERS"
|
||||
| "MANAGE_STAFF"
|
||||
| "IMPERSONATE_USER"
|
||||
| "MANAGE_APPS"
|
||||
| "MANAGE_OBSERVABILITY"
|
||||
| "MANAGE_CHECKOUTS"
|
||||
| "HANDLE_CHECKOUTS"
|
||||
|
|
Loading…
Reference in a new issue