Skip to content

Commit

Permalink
Merge pull request #838 from commercelayer/token-provider
Browse files Browse the repository at this point in the history
Add storage methods in `TokenProvider`
  • Loading branch information
gciotola authored Nov 27, 2024
2 parents 170ea68 + 4b6b980 commit bc70bfa
Show file tree
Hide file tree
Showing 3 changed files with 88 additions and 23 deletions.
44 changes: 44 additions & 0 deletions .github/workflows/pkg-pr-new.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
name: pkg-pr-new

on:
push:
branches:
- "**"
- "!main"
- "!release"
tags-ignore:
- "v*"
pull_request:
types: [ready_for_review]
branches-ignore:
- release

jobs:
publish:
runs-on: ubuntu-latest

steps:
- name: Checkout 🛎️
uses: actions/checkout@v4
with:
persist-credentials: false

- name: pnpm 🧰
uses: pnpm/action-setup@v3
with:
version: 9.x

- name: Node 🧰
uses: actions/setup-node@v4
with:
node-version: 22.x

- name: Install 📦
run: pnpm install --frozen-lockfile

- name: Build elements 🛠
run: pnpm build:elements

- name: Publish 🚀 pkg.pr.new
run: |
npx pkg-pr-new publish './packages/app-elements' --no-template
58 changes: 43 additions & 15 deletions packages/app-elements/src/providers/TokenProvider/TokenProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -68,11 +68,24 @@ export interface TokenProviderProps {
children: ((props: TokenProviderValue) => ReactNode) | ReactNode
/**
* If present, only an access token with the same organization slug will be considered valid.
* It will be also used to generate the local storage key when the token is persisted.
* It will be also used to generate the local storage key when the token is persisted (unless a custom `storage` methods are provided).
* When empty, the app will use the organization slug decoded from the token
* and the token will be persisted using a default key ('commercelayer').
*/
organizationSlug?: string
/**
* Optional. Override the internal logic to persist the access token and extra (save and retrieve).
*/
storage?: {
/** Custom method to retrieve the access token. It must return a valid and not expired access token */
getAccessToken: () => string | null
/** Custom method to save the access token in your preferred storage */
saveAccessToken: (token: string) => void
/** Custom method to retrieve the encoded `extra` data, if provided */
getEncodedExtra?: () => string | null
/** Custom method to save the encoded `extra` data, if provided, in your preferred storage */
saveEncodedExtra?: (encodedExtra: string) => void
}
/**
* The callback invoked when token is not valid.
* Can be used to manually handle the re-authentication flow when `reauthenticateOnInvalidAuth` is false.
Expand Down Expand Up @@ -130,6 +143,7 @@ export const TokenProvider: React.FC<TokenProviderProps> = ({
devMode,
children,
organizationSlug,
storage,
onInvalidAuth,
loadingElement,
errorElement,
Expand All @@ -139,15 +153,23 @@ export const TokenProvider: React.FC<TokenProviderProps> = ({
extras: extrasFromProp
}) => {
const [_state, dispatch] = useReducer(reducer, initialTokenProviderState)

const accessToken =
accessTokenFromProp ??
getAccessTokenFromUrl() ??
getPersistentJWT({ appSlug, organizationSlug, itemType: 'accessToken' })
(storage?.getAccessToken != null
? storage?.getAccessToken()
: getPersistentJWT({
appSlug,
organizationSlug,
itemType: 'accessToken'
}))

const encodeExtras =
getExtrasFromUrl() ??
getPersistentJWT({ appSlug, organizationSlug, itemType: 'extras' })
(storage?.getEncodedExtra != null
? storage?.getEncodedExtra()
: getPersistentJWT({ appSlug, organizationSlug, itemType: 'extras' }))

const extras = extrasFromProp ?? decodeExtras(encodeExtras)

const apiBaseEndpoint =
Expand Down Expand Up @@ -228,23 +250,29 @@ export const TokenProvider: React.FC<TokenProviderProps> = ({
})
: null

// all good
savePersistentJWT({
appSlug,
jwt: accessToken,
organizationSlug,
itemType: 'accessToken'
})

if (encodeExtras != null) {
// all good - save token using custom storage method (if provided) or fallback to internal method
if (storage != null) {
storage.saveAccessToken(accessToken)
} else {
savePersistentJWT({
appSlug,
jwt: encodeExtras,
jwt: accessToken,
organizationSlug,
itemType: 'extras'
itemType: 'accessToken'
})
}

if (encodeExtras != null) {
storage != null
? storage.saveEncodedExtra?.(encodeExtras)
: savePersistentJWT({
appSlug,
jwt: encodeExtras,
organizationSlug,
itemType: 'extras'
})
}

removeAuthParamsFromUrl()

const userFromExtras =
Expand Down
9 changes: 1 addition & 8 deletions packages/app-elements/src/providers/createApp.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,19 +28,12 @@ declare global {
}

export interface ClAppProps
extends Pick<
TokenProviderProps,
'organizationSlug' | 'onAppClose' | 'isInDashboard' | 'extras'
> {
extends Partial<Omit<TokenProviderProps, 'appSlug' | 'children'>> {
/**
* Base path for internal routing.
* Example: `my-app` if you want to serve the app at `https://my-domain.com/my-app/`.
*/
routerBase?: string
/**
* Callback to be called when the user is not authenticated or the token is invalid/expired.
*/
onInvalidAuth?: () => void
}

/**
Expand Down

0 comments on commit bc70bfa

Please sign in to comment.