gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[taler-wallet-core] branch master updated: fix #8604


From: gnunet
Subject: [taler-wallet-core] branch master updated: fix #8604
Date: Mon, 15 Apr 2024 17:01:25 +0200

This is an automated email from the git hooks/post-receive script.

sebasjm pushed a commit to branch master
in repository wallet-core.

The following commit(s) were added to refs/heads/master by this push:
     new a7c8f0f3e fix #8604
a7c8f0f3e is described below

commit a7c8f0f3edd738a59d719105cda3aa8821886b90
Author: Sebastian <sebasjm@gmail.com>
AuthorDate: Mon Apr 15 12:01:16 2024 -0300

    fix #8604
---
 .../merchant-backoffice-ui/src/Application.tsx     | 383 +++++++++++----------
 packages/merchant-backoffice-ui/src/Routing.tsx    |  10 +-
 .../src/components/form/InputCurrency.tsx          |   3 +-
 .../instance/DefaultInstanceFormFields.tsx         |   5 +-
 .../src/components/menu/SideBar.tsx                |  21 +-
 .../src/components/menu/index.tsx                  |  13 +-
 .../src/components/product/ProductForm.tsx         |  13 +-
 .../merchant-backoffice-ui/src/context/session.ts  | 282 ++++++++-------
 packages/merchant-backoffice-ui/src/hooks/bank.ts  |   9 +-
 .../merchant-backoffice-ui/src/hooks/instance.ts   |  11 +-
 packages/merchant-backoffice-ui/src/hooks/order.ts |   7 +-
 packages/merchant-backoffice-ui/src/hooks/otp.ts   |   9 +-
 .../merchant-backoffice-ui/src/hooks/product.ts    |   7 +-
 .../merchant-backoffice-ui/src/hooks/templates.ts  |   7 +-
 .../merchant-backoffice-ui/src/hooks/transfer.ts   |   5 +-
 .../merchant-backoffice-ui/src/hooks/webhooks.ts   |   9 +-
 .../src/paths/admin/create/CreatePage.tsx          |  45 ++-
 .../src/paths/admin/create/index.tsx               |   7 +-
 .../src/paths/admin/list/TableActive.tsx           |  13 +-
 .../src/paths/admin/list/index.tsx                 |   5 +-
 .../src/paths/instance/accounts/create/index.tsx   |   9 +-
 .../src/paths/instance/accounts/list/index.tsx     |   5 +-
 .../src/paths/instance/accounts/update/index.tsx   |   5 +-
 .../src/paths/instance/details/index.tsx           |   5 +-
 .../paths/instance/orders/create/CreatePage.tsx    |   7 +-
 .../src/paths/instance/orders/create/index.tsx     |   7 +-
 .../paths/instance/orders/details/DetailPage.tsx   |   8 +-
 .../src/paths/instance/orders/details/index.tsx    |   7 +-
 .../src/paths/instance/orders/list/Table.tsx       |   6 +-
 .../src/paths/instance/orders/list/index.tsx       |   7 +-
 .../otp_devices/create/CreatedSuccessfully.tsx     |   5 +-
 .../paths/instance/otp_devices/create/index.tsx    |  10 +-
 .../src/paths/instance/otp_devices/list/index.tsx  |   5 +-
 .../paths/instance/otp_devices/update/index.tsx    |   5 +-
 .../src/paths/instance/products/create/index.tsx   |   8 +-
 .../src/paths/instance/products/list/index.tsx     |   5 +-
 .../src/paths/instance/products/update/index.tsx   |   5 +-
 .../paths/instance/templates/create/CreatePage.tsx |   9 +-
 .../src/paths/instance/templates/create/index.tsx  |   4 +-
 .../src/paths/instance/templates/list/index.tsx    |   5 +-
 .../src/paths/instance/templates/qr/QrPage.tsx     |  24 +-
 .../paths/instance/templates/update/UpdatePage.tsx |   9 +-
 .../src/paths/instance/templates/update/index.tsx  |   5 +-
 .../src/paths/instance/templates/use/index.tsx     |   6 +-
 .../src/paths/instance/token/DetailPage.tsx        |  18 +-
 .../src/paths/instance/token/index.tsx             |  98 ++++--
 .../src/paths/instance/transfers/create/index.tsx  |   9 +-
 .../src/paths/instance/update/index.tsx            |   7 +-
 .../src/paths/instance/webhooks/create/index.tsx   |  10 +-
 .../src/paths/instance/webhooks/list/index.tsx     |   7 +-
 .../src/paths/instance/webhooks/update/index.tsx   |   5 +-
 .../src/paths/login/index.tsx                      | 119 +------
 packages/taler-harness/src/index.ts                |  96 ++++--
 packages/taler-util/src/codec.ts                   |  34 ++
 .../taler-util/src/http-client/authentication.ts   |   4 +-
 packages/taler-util/src/http-client/types.ts       |  16 +-
 packages/taler-util/src/http-client/utils.ts       |   2 +-
 packages/web-util/src/context/activity.ts          |   2 +-
 packages/web-util/src/context/merchant-api.ts      |  34 +-
 59 files changed, 719 insertions(+), 777 deletions(-)

diff --git a/packages/merchant-backoffice-ui/src/Application.tsx 
b/packages/merchant-backoffice-ui/src/Application.tsx
index d5a05e821..097e98567 100644
--- a/packages/merchant-backoffice-ui/src/Application.tsx
+++ b/packages/merchant-backoffice-ui/src/Application.tsx
@@ -19,14 +19,21 @@
  * @author Sebastian Javier Marchano (sebasjm)
  */
 
-import { CacheEvictor, TalerMerchantApi, TalerMerchantInstanceCacheEviction, 
TalerMerchantManagementCacheEviction, assertUnreachable, canonicalizeBaseUrl } 
from "@gnu-taler/taler-util";
+import {
+  CacheEvictor,
+  TalerMerchantApi,
+  TalerMerchantInstanceCacheEviction,
+  TalerMerchantManagementCacheEviction,
+  assertUnreachable,
+  canonicalizeBaseUrl,
+} from "@gnu-taler/taler-util";
 import {
   BrowserHashNavigationProvider,
   ConfigResultFail,
   MerchantApiProvider,
   TalerWalletIntegrationBrowserProvider,
   TranslationProvider,
-  useTranslationContext
+  useTranslationContext,
 } from "@gnu-taler/web-util/browser";
 import { VNode, h } from "preact";
 import { useEffect, useState } from "preact/hooks";
@@ -35,16 +42,43 @@ import { Routing } from "./Routing.js";
 import { Loading } from "./components/exception/loading.js";
 import { NotificationCard } from "./components/menu/index.js";
 import { SettingsProvider } from "./context/settings.js";
-import { revalidateBankAccountDetails, revalidateInstanceBankAccounts } from 
"./hooks/bank.js";
-import { revalidateBackendInstances, revalidateInstanceDetails, 
revalidateManagedInstanceDetails } from "./hooks/instance.js";
-import { revalidateInstanceOtpDevices, revalidateOtpDeviceDetails } from 
"./hooks/otp.js";
-import { revalidateInstanceProducts, revalidateProductDetails } from 
"./hooks/product.js";
-import { revalidateInstanceTemplates, revalidateTemplateDetails } from 
"./hooks/templates.js";
+import {
+  revalidateBankAccountDetails,
+  revalidateInstanceBankAccounts,
+} from "./hooks/bank.js";
+import {
+  revalidateBackendInstances,
+  revalidateInstanceDetails,
+  revalidateManagedInstanceDetails,
+} from "./hooks/instance.js";
+import {
+  revalidateInstanceOtpDevices,
+  revalidateOtpDeviceDetails,
+} from "./hooks/otp.js";
+import {
+  revalidateInstanceProducts,
+  revalidateProductDetails,
+} from "./hooks/product.js";
+import {
+  revalidateInstanceTemplates,
+  revalidateTemplateDetails,
+} from "./hooks/templates.js";
 import { revalidateInstanceTransfers } from "./hooks/transfer.js";
-import { revalidateInstanceWebhooks, revalidateWebhookDetails } from 
"./hooks/webhooks.js";
+import {
+  revalidateInstanceWebhooks,
+  revalidateWebhookDetails,
+} from "./hooks/webhooks.js";
 import { strings } from "./i18n/strings.js";
-import { MerchantUiSettings, buildDefaultBackendBaseURL, fetchSettings } from 
"./settings.js";
-import { revalidateInstanceOrders, revalidateOrderDetails } from 
"./hooks/order.js";
+import {
+  MerchantUiSettings,
+  buildDefaultBackendBaseURL,
+  fetchSettings,
+} from "./settings.js";
+import {
+  revalidateInstanceOrders,
+  revalidateOrderDetails,
+} from "./hooks/order.js";
+import { SessionContextProvider } from "./context/session.js";
 const WITH_LOCAL_STORAGE_CACHE = false;
 
 export function Application(): VNode {
@@ -64,42 +98,48 @@ export function Application(): VNode {
           de: strings["de"].completeness,
         }}
       >
-        <MerchantApiProvider baseUrl={new URL("./", baseUrl)} 
frameOnError={OnConfigError} evictors={{
-          management: swrCacheEvictor
-        }}>
-          <SWRConfig
-            value={{
-              provider: WITH_LOCAL_STORAGE_CACHE
-                ? localStorageProvider
-                : undefined,
-              // normally, do not revalidate
-              revalidateOnFocus: false,
-              revalidateOnReconnect: false,
-              revalidateIfStale: false,
-              revalidateOnMount: undefined,
-              focusThrottleInterval: undefined,
+        <MerchantApiProvider
+          baseUrl={new URL("./", baseUrl)}
+          frameOnError={OnConfigError}
+          evictors={{
+            management: swrCacheEvictor,
+          }}
+        >
+          <SessionContextProvider>
+            <SWRConfig
+              value={{
+                provider: WITH_LOCAL_STORAGE_CACHE
+                  ? localStorageProvider
+                  : undefined,
+                // normally, do not revalidate
+                revalidateOnFocus: false,
+                revalidateOnReconnect: false,
+                revalidateIfStale: false,
+                revalidateOnMount: undefined,
+                focusThrottleInterval: undefined,
 
-              // normally, do not refresh
-              refreshInterval: undefined,
-              dedupingInterval: 2000,
-              refreshWhenHidden: false,
-              refreshWhenOffline: false,
+                // normally, do not refresh
+                refreshInterval: undefined,
+                dedupingInterval: 2000,
+                refreshWhenHidden: false,
+                refreshWhenOffline: false,
 
-              // ignore errors
-              shouldRetryOnError: false,
-              errorRetryCount: 0,
-              errorRetryInterval: undefined,
+                // ignore errors
+                shouldRetryOnError: false,
+                errorRetryCount: 0,
+                errorRetryInterval: undefined,
 
-              // do not go to loading again if already has data
-              keepPreviousData: true,
-            }}
-          >
-            <TalerWalletIntegrationBrowserProvider>
-              <BrowserHashNavigationProvider>
-                <Routing />
-              </BrowserHashNavigationProvider>
-            </TalerWalletIntegrationBrowserProvider>
-          </SWRConfig>
+                // do not go to loading again if already has data
+                keepPreviousData: true,
+              }}
+            >
+              <TalerWalletIntegrationBrowserProvider>
+                <BrowserHashNavigationProvider>
+                  <Routing />
+                </BrowserHashNavigationProvider>
+              </TalerWalletIntegrationBrowserProvider>
+            </SWRConfig>
+          </SessionContextProvider>
         </MerchantApiProvider>
       </TranslationProvider>
     </SettingsProvider>
@@ -150,187 +190,157 @@ function localStorageProvider(): Map<unknown, unknown> {
   return map;
 }
 
-function OnConfigError({ state }: { state: 
ConfigResultFail<TalerMerchantApi.VersionResponse> | undefined }): VNode {
+function OnConfigError({
+  state,
+}: {
+  state: ConfigResultFail<TalerMerchantApi.VersionResponse> | undefined;
+}): VNode {
   const { i18n } = useTranslationContext();
   if (!state) {
-    return <i18n.Translate>checking compatibility with 
server...</i18n.Translate>
+    return (
+      <i18n.Translate>checking compatibility with server...</i18n.Translate>
+    );
   }
   switch (state.type) {
     case "error": {
-      return <NotificationCard
-        notification={{
-          message: i18n.str`Contacting the server failed`,
-          description: state.error.message,
-          details: JSON.stringify(state.error.errorDetail, undefined, 2),
-          type: "ERROR",
-        }}
-      />
+      return (
+        <NotificationCard
+          notification={{
+            message: i18n.str`Contacting the server failed`,
+            description: state.error.message,
+            details: JSON.stringify(state.error.errorDetail, undefined, 2),
+            type: "ERROR",
+          }}
+        />
+      );
     }
     case "incompatible": {
-      return <NotificationCard
-        notification={{
-          message: i18n.str`The server version is not supported`,
-          description: i18n.str`Supported version "${state.supported}", server 
version "${state.result.version}".`,
-          type: "WARN",
-        }}
-      />
+      return (
+        <NotificationCard
+          notification={{
+            message: i18n.str`The server version is not supported`,
+            description: i18n.str`Supported version "${state.supported}", 
server version "${state.result.version}".`,
+            type: "WARN",
+          }}
+        />
+      );
     }
-    default: assertUnreachable(state)
+    default:
+      assertUnreachable(state);
   }
 }
 
-const swrCacheEvictor= new class implements 
CacheEvictor<TalerMerchantManagementCacheEviction | 
TalerMerchantInstanceCacheEviction> {
-  async notifySuccess(op: TalerMerchantManagementCacheEviction | 
TalerMerchantInstanceCacheEviction) {
-    switch(op) {
+const swrCacheEvictor = new (class
+  implements
+    CacheEvictor<
+      TalerMerchantManagementCacheEviction | TalerMerchantInstanceCacheEviction
+    >
+{
+  async notifySuccess(
+    op:
+      | TalerMerchantManagementCacheEviction
+      | TalerMerchantInstanceCacheEviction,
+  ) {
+    switch (op) {
       case TalerMerchantManagementCacheEviction.CREATE_INSTANCE: {
-        await Promise.all([
-          revalidateBackendInstances()
-        ])
-        return
+        await Promise.all([revalidateBackendInstances()]);
+        return;
       }
       case TalerMerchantManagementCacheEviction.UPDATE_INSTANCE: {
-        await Promise.all([
-          revalidateManagedInstanceDetails()
-        ])
-        return
+        await Promise.all([revalidateManagedInstanceDetails()]);
+        return;
       }
-      case TalerMerchantManagementCacheEviction.DELETE_INSTANCE:{
-        await Promise.all([
-          revalidateBackendInstances()
-        ])
-        return
+      case TalerMerchantManagementCacheEviction.DELETE_INSTANCE: {
+        await Promise.all([revalidateBackendInstances()]);
+        return;
       }
-      case TalerMerchantInstanceCacheEviction.UPDATE_CURRENT_INSTANCE:{
-        await Promise.all([
-          revalidateInstanceDetails()
-        ])
-        return
+      case TalerMerchantInstanceCacheEviction.UPDATE_CURRENT_INSTANCE: {
+        await Promise.all([revalidateInstanceDetails()]);
+        return;
       }
-      case TalerMerchantInstanceCacheEviction.DELETE_CURRENT_INSTANCE:{
-        await Promise.all([
-          revalidateInstanceDetails()
-        ])
-        return
+      case TalerMerchantInstanceCacheEviction.DELETE_CURRENT_INSTANCE: {
+        await Promise.all([revalidateInstanceDetails()]);
+        return;
       }
-      case TalerMerchantInstanceCacheEviction.CREATE_BANK_ACCOUNT:{
-        await Promise.all([
-          revalidateInstanceBankAccounts()
-        ])
-        return
+      case TalerMerchantInstanceCacheEviction.CREATE_BANK_ACCOUNT: {
+        await Promise.all([revalidateInstanceBankAccounts()]);
+        return;
       }
-      case TalerMerchantInstanceCacheEviction.UPDATE_BANK_ACCOUNT:{
-        await Promise.all([
-          revalidateBankAccountDetails()
-        ])
-        return
+      case TalerMerchantInstanceCacheEviction.UPDATE_BANK_ACCOUNT: {
+        await Promise.all([revalidateBankAccountDetails()]);
+        return;
       }
-      case TalerMerchantInstanceCacheEviction.DELETE_BANK_ACCOUNT:{
-        await Promise.all([
-          revalidateInstanceBankAccounts()
-        ])
-        return
+      case TalerMerchantInstanceCacheEviction.DELETE_BANK_ACCOUNT: {
+        await Promise.all([revalidateInstanceBankAccounts()]);
+        return;
       }
-      case TalerMerchantInstanceCacheEviction.CREATE_PRODUCT:{
-        await Promise.all([
-          revalidateInstanceProducts()
-        ])
-        return
+      case TalerMerchantInstanceCacheEviction.CREATE_PRODUCT: {
+        await Promise.all([revalidateInstanceProducts()]);
+        return;
       }
-      case TalerMerchantInstanceCacheEviction.UPDATE_PRODUCT:{
-        await Promise.all([
-          revalidateProductDetails()
-        ])
-        return
+      case TalerMerchantInstanceCacheEviction.UPDATE_PRODUCT: {
+        await Promise.all([revalidateProductDetails()]);
+        return;
       }
-      case TalerMerchantInstanceCacheEviction.DELETE_PRODUCT:{
-        await Promise.all([
-          revalidateInstanceProducts()
-        ])
-        return
+      case TalerMerchantInstanceCacheEviction.DELETE_PRODUCT: {
+        await Promise.all([revalidateInstanceProducts()]);
+        return;
       }
-      case TalerMerchantInstanceCacheEviction.CREATE_TRANSFER:{
-        await Promise.all([
-          revalidateInstanceTransfers()
-        ])
-        return
+      case TalerMerchantInstanceCacheEviction.CREATE_TRANSFER: {
+        await Promise.all([revalidateInstanceTransfers()]);
+        return;
       }
-      case TalerMerchantInstanceCacheEviction.DELETE_TRANSFER:{
-        await Promise.all([
-          revalidateInstanceTransfers()
-        ])
-        return
+      case TalerMerchantInstanceCacheEviction.DELETE_TRANSFER: {
+        await Promise.all([revalidateInstanceTransfers()]);
+        return;
       }
-      case TalerMerchantInstanceCacheEviction.CREATE_DEVICE:{
-        await Promise.all([
-          revalidateInstanceOtpDevices()
-        ])
-        return
+      case TalerMerchantInstanceCacheEviction.CREATE_DEVICE: {
+        await Promise.all([revalidateInstanceOtpDevices()]);
+        return;
       }
-      case TalerMerchantInstanceCacheEviction.UPDATE_DEVICE:{
-        await Promise.all([
-          revalidateOtpDeviceDetails()
-        ])
-        return
+      case TalerMerchantInstanceCacheEviction.UPDATE_DEVICE: {
+        await Promise.all([revalidateOtpDeviceDetails()]);
+        return;
       }
-      case TalerMerchantInstanceCacheEviction.DELETE_DEVICE:{
-        await Promise.all([
-          revalidateInstanceOtpDevices()
-        ])
-        return
+      case TalerMerchantInstanceCacheEviction.DELETE_DEVICE: {
+        await Promise.all([revalidateInstanceOtpDevices()]);
+        return;
       }
-      case TalerMerchantInstanceCacheEviction.CREATE_TEMPLATE:{
-        await Promise.all([
-          revalidateInstanceTemplates()
-        ])
-        return
+      case TalerMerchantInstanceCacheEviction.CREATE_TEMPLATE: {
+        await Promise.all([revalidateInstanceTemplates()]);
+        return;
       }
-      case TalerMerchantInstanceCacheEviction.UPDATE_TEMPLATE:{
-        await Promise.all([
-          revalidateTemplateDetails()
-        ])
-        return
+      case TalerMerchantInstanceCacheEviction.UPDATE_TEMPLATE: {
+        await Promise.all([revalidateTemplateDetails()]);
+        return;
       }
-      case TalerMerchantInstanceCacheEviction.DELETE_TEMPLATE:{
-        await Promise.all([
-          revalidateInstanceTemplates()
-        ])
-        return
+      case TalerMerchantInstanceCacheEviction.DELETE_TEMPLATE: {
+        await Promise.all([revalidateInstanceTemplates()]);
+        return;
       }
-      case TalerMerchantInstanceCacheEviction.CREATE_WEBHOOK:{
-        await Promise.all([
-          revalidateInstanceWebhooks()
-        ])
-        return
+      case TalerMerchantInstanceCacheEviction.CREATE_WEBHOOK: {
+        await Promise.all([revalidateInstanceWebhooks()]);
+        return;
       }
-      case TalerMerchantInstanceCacheEviction.UPDATE_WEBHOOK:{
-        await Promise.all([
-          revalidateWebhookDetails()
-        ])
-        return
+      case TalerMerchantInstanceCacheEviction.UPDATE_WEBHOOK: {
+        await Promise.all([revalidateWebhookDetails()]);
+        return;
       }
-      case TalerMerchantInstanceCacheEviction.DELETE_WEBHOOK:{
-        await Promise.all([
-          revalidateInstanceWebhooks()
-        ])
-        return
+      case TalerMerchantInstanceCacheEviction.DELETE_WEBHOOK: {
+        await Promise.all([revalidateInstanceWebhooks()]);
+        return;
       }
-      case TalerMerchantInstanceCacheEviction.CREATE_ORDER:{
-        await Promise.all([
-          revalidateInstanceOrders()
-        ])
-        return
+      case TalerMerchantInstanceCacheEviction.CREATE_ORDER: {
+        await Promise.all([revalidateInstanceOrders()]);
+        return;
       }
       case TalerMerchantInstanceCacheEviction.UPDATE_ORDER: {
-        await Promise.all([
-          revalidateOrderDetails()
-        ])
-        return
+        await Promise.all([revalidateOrderDetails()]);
+        return;
       }
       case TalerMerchantInstanceCacheEviction.DELETE_ORDER: {
-        await Promise.all([
-          revalidateInstanceOrders()
-        ])
-        return
+        await Promise.all([revalidateInstanceOrders()]);
+        return;
       }
       case TalerMerchantInstanceCacheEviction.LAST:
       // case TalerMerchantInstanceCacheEviction.CREATE_TOKENFAMILY:{
@@ -351,5 +361,4 @@ const swrCacheEvictor= new class implements 
CacheEvictor<TalerMerchantManagement
       // }
     }
   }
-
-}
+})();
diff --git a/packages/merchant-backoffice-ui/src/Routing.tsx 
b/packages/merchant-backoffice-ui/src/Routing.tsx
index 66f352118..665137415 100644
--- a/packages/merchant-backoffice-ui/src/Routing.tsx
+++ b/packages/merchant-backoffice-ui/src/Routing.tsx
@@ -22,12 +22,9 @@
 import {
   AbsoluteTime,
   TalerError,
-  TranslatedString
+  TranslatedString,
 } from "@gnu-taler/taler-util";
-import {
-  urlPattern,
-  useTranslationContext
-} from "@gnu-taler/web-util/browser";
+import { urlPattern, useTranslationContext } from 
"@gnu-taler/web-util/browser";
 import { createHashHistory } from "history";
 import { Fragment, VNode, h } from "preact";
 import { Route, Router, route } from "preact-router";
@@ -168,8 +165,7 @@ export function Routing(_p: Props): VNode {
     (AbsoluteTime.isNever(preference.hideMissingAccountUntil) ||
       AbsoluteTime.cmp(now, preference.hideMissingAccountUntil) > 1);
 
-  const shouldLogin =
-    state.status === "loggedOut" || state.status === "expired";
+  const shouldLogin = state.status === "loggedOut";
 
   // function ServerErrorRedirectTo(to: InstancePaths | AdminPaths) {
   //   return function ServerErrorRedirectToImpl(
diff --git 
a/packages/merchant-backoffice-ui/src/components/form/InputCurrency.tsx 
b/packages/merchant-backoffice-ui/src/components/form/InputCurrency.tsx
index 76d38db84..11396b88e 100644
--- a/packages/merchant-backoffice-ui/src/components/form/InputCurrency.tsx
+++ b/packages/merchant-backoffice-ui/src/components/form/InputCurrency.tsx
@@ -23,6 +23,7 @@ import { ComponentChildren, h, VNode } from "preact";
 import { InputWithAddon } from "./InputWithAddon.js";
 import { InputProps } from "./useField.js";
 import { AmountString } from "@gnu-taler/taler-util";
+import { useSessionContext } from "../../context/session.js";
 
 export interface Props<T> extends InputProps<T> {
   expand?: boolean;
@@ -43,7 +44,7 @@ export function InputCurrency<T>({
   children,
   side,
 }: Props<keyof T>): VNode {
-  const { config } = useMerchantApiContext();
+  const { config } = useSessionContext();
   return (
     <InputWithAddon<T>
       name={name}
diff --git 
a/packages/merchant-backoffice-ui/src/components/instance/DefaultInstanceFormFields.tsx
 
b/packages/merchant-backoffice-ui/src/components/instance/DefaultInstanceFormFields.tsx
index 2a24dfbe2..dd41b6fbd 100644
--- 
a/packages/merchant-backoffice-ui/src/components/instance/DefaultInstanceFormFields.tsx
+++ 
b/packages/merchant-backoffice-ui/src/components/instance/DefaultInstanceFormFields.tsx
@@ -33,6 +33,7 @@ import { InputLocation } from "../form/InputLocation.js";
 import { InputSelector } from "../form/InputSelector.js";
 import { InputToggle } from "../form/InputToggle.js";
 import { InputWithAddon } from "../form/InputWithAddon.js";
+import { useSessionContext } from "../../context/session.js";
 
 export function DefaultInstanceFormFields({
   readonlyId,
@@ -42,13 +43,13 @@ export function DefaultInstanceFormFields({
   showId: boolean;
 }): VNode {
   const { i18n } = useTranslationContext();
-  const { url: backendUrl } = useMerchantApiContext();
+  const { state } = useSessionContext();
   return (
     <Fragment>
       {showId && (
         <InputWithAddon<Entity>
           name="id"
-          addonBefore={new URL("instances/", backendUrl.href).href}
+          addonBefore={new URL("instances/", state.backendUrl.href).href}
           readonly={readonlyId}
           label={i18n.str`Identifier`}
           tooltip={i18n.str`Name of the instance in URLs. The 'default' 
instance is special in that it is used to administer other instances.`}
diff --git a/packages/merchant-backoffice-ui/src/components/menu/SideBar.tsx 
b/packages/merchant-backoffice-ui/src/components/menu/SideBar.tsx
index 9819c1911..2090704d9 100644
--- a/packages/merchant-backoffice-ui/src/components/menu/SideBar.tsx
+++ b/packages/merchant-backoffice-ui/src/components/menu/SideBar.tsx
@@ -19,15 +19,12 @@
  * @author Sebastian Javier Marchano (sebasjm)
  */
 
-import {
-  useMerchantApiContext,
-  useTranslationContext,
-} from "@gnu-taler/web-util/browser";
+import { TalerError } from "@gnu-taler/taler-util";
+import { useTranslationContext } from "@gnu-taler/web-util/browser";
 import { Fragment, VNode, h } from "preact";
 import { useSessionContext } from "../../context/session.js";
 import { useInstanceKYCDetails } from "../../hooks/instance.js";
 import { LangSelector } from "./LangSelector.js";
-import { TalerError } from "@gnu-taler/taler-util";
 
 // const GIT_HASH = typeof __GIT_HASH__ !== "undefined" ? __GIT_HASH__ : 
undefined;
 const VERSION = typeof __VERSION__ !== "undefined" ? __VERSION__ : undefined;
@@ -38,6 +35,7 @@ interface Props {
 
 export function Sidebar({ mobile }: Props): VNode {
   const { i18n } = useTranslationContext();
+  const { state, logOut, config } = useSessionContext();
   const kycStatus = useInstanceKYCDetails();
 
   const needKYC =
@@ -45,11 +43,9 @@ export function Sidebar({ mobile }: Props): VNode {
     !(kycStatus instanceof TalerError) &&
     kycStatus.type === "ok" &&
     !!kycStatus.body;
-  const { state, logOut } = useSessionContext();
   const isLoggedIn = state.status === "loggedIn";
   const hasToken = isLoggedIn && state.token !== undefined;
-  const { config, url: backendURL } = useMerchantApiContext();
-
+  
   return (
     <aside
       class="aside is-placed-left is-expanded"
@@ -195,10 +191,7 @@ export function Sidebar({ mobile }: Props): VNode {
         </p>
         <ul class="menu-list">
           <li>
-            <a
-              class="has-icon is-state-info is-hoverable"
-              href="/interface"
-            >
+            <a class="has-icon is-state-info is-hoverable" href="/interface">
               <span class="icon">
                 <i class="mdi mdi-newspaper" />
               </span>
@@ -212,9 +205,7 @@ export function Sidebar({ mobile }: Props): VNode {
               <span style={{ width: "3rem" }} class="icon">
                 <i class="mdi mdi-web" />
               </span>
-              <span class="menu-item-label">
-                {backendURL.hostname}
-              </span>
+              <span class="menu-item-label">{state.backendUrl.hostname}</span>
             </div>
           </li>
           <li>
diff --git a/packages/merchant-backoffice-ui/src/components/menu/index.tsx 
b/packages/merchant-backoffice-ui/src/components/menu/index.tsx
index aa955db4e..a35c07ace 100644
--- a/packages/merchant-backoffice-ui/src/components/menu/index.tsx
+++ b/packages/merchant-backoffice-ui/src/components/menu/index.tsx
@@ -104,7 +104,7 @@ export function Menu(_p: MenuProps): VNode {
     ? getInstanceTitle(path, state.instance)
     : getAdminTitle(path, state.instance);
 
-  const isLoggedIn =state.status === "loggedIn";
+  const isLoggedIn = state.status === "loggedIn";
 
   return (
     <WithTitle title={titleWithSubtitle}>
@@ -117,11 +117,9 @@ export function Menu(_p: MenuProps): VNode {
           title={titleWithSubtitle}
         />
 
-        {isLoggedIn && (
-          <Sidebar mobile={mobileOpen} />
-        )}
+        {isLoggedIn && <Sidebar mobile={mobileOpen} />}
 
-        {state.status !== "loggedOut" && state.impersonate !== undefined && (
+        {state.status !== "loggedOut" && state.impersonated && (
           <nav
             class="level"
             style={{
@@ -137,9 +135,8 @@ export function Menu(_p: MenuProps): VNode {
                 .{" "}
                 <a
                   href="#/instances"
-                  onClick={(e) => {
+                  onClick={() => {
                     deImpersonate();
-                    e.preventDefault();
                   }}
                 >
                   go back
@@ -228,7 +225,7 @@ export function NotYetReadyAppMenu({ title }: 
NotYetReadyAppMenuProps): VNode {
   useEffect(() => {
     document.title = `Taler Backoffice: ${title}`;
   }, [title]);
-  
+
   const isLoggedIn = state.status === "loggedIn";
 
   return (
diff --git 
a/packages/merchant-backoffice-ui/src/components/product/ProductForm.tsx 
b/packages/merchant-backoffice-ui/src/components/product/ProductForm.tsx
index 781d2de2c..c6d687b85 100644
--- a/packages/merchant-backoffice-ui/src/components/product/ProductForm.tsx
+++ b/packages/merchant-backoffice-ui/src/components/product/ProductForm.tsx
@@ -20,13 +20,11 @@
  */
 
 import { AmountString, TalerMerchantApi } from "@gnu-taler/taler-util";
-import {
-  useMerchantApiContext,
-  useTranslationContext
-} from "@gnu-taler/web-util/browser";
+import { useTranslationContext } from "@gnu-taler/web-util/browser";
 import { h } from "preact";
 import { useCallback, useEffect, useState } from "preact/hooks";
 import * as yup from "yup";
+import { useSessionContext } from "../../context/session.js";
 import {
   ProductCreateSchema as createSchema,
   ProductUpdateSchema as updateSchema,
@@ -88,7 +86,7 @@ export function ProductForm({ onSubscribe, initial, 
alreadyExist }: Props) {
   );
 
   const submit = useCallback((): Entity | undefined => {
-    const stock = (value).stock;
+    const stock = value.stock;
 
     if (!stock) {
       value.total_stock = -1;
@@ -116,9 +114,8 @@ export function ProductForm({ onSubscribe, initial, 
alreadyExist }: Props) {
     onSubscribe(hasErrors ? undefined : submit);
   }, [submit, hasErrors]);
 
-  const { url: backendUrl } = useMerchantApiContext();
   const { i18n } = useTranslationContext();
-
+  const { state } = useSessionContext();
   return (
     <div>
       <FormProvider<Entity>
@@ -130,7 +127,7 @@ export function ProductForm({ onSubscribe, initial, 
alreadyExist }: Props) {
         {alreadyExist ? undefined : (
           <InputWithAddon<Entity>
             name="product_id"
-            addonBefore={new URL("product/", backendUrl.href).href}
+            addonBefore={new URL("product/", state.backendUrl.href).href}
             label={i18n.str`ID`}
             tooltip={i18n.str`product identification to use in URLs (for 
internal use only)`}
           />
diff --git a/packages/merchant-backoffice-ui/src/context/session.ts 
b/packages/merchant-backoffice-ui/src/context/session.ts
index 6d01464e0..fb1b7b374 100644
--- a/packages/merchant-backoffice-ui/src/context/session.ts
+++ b/packages/merchant-backoffice-ui/src/context/session.ts
@@ -17,11 +17,10 @@
 import {
   AccessToken,
   Codec,
+  TalerMerchantApi,
   buildCodecForObject,
-  buildCodecForUnion,
-  codecForBoolean,
-  codecForConstString,
   codecForString,
+  codecForURL,
   codecOptional,
 } from "@gnu-taler/taler-util";
 import {
@@ -29,99 +28,79 @@ import {
   useLocalStorage,
   useMerchantApiContext,
 } from "@gnu-taler/web-util/browser";
+import { ComponentChildren, VNode, createContext, h } from "preact";
+import { useContext, useEffect, useState } from "preact/hooks";
 import { mutate } from "swr";
+import { MerchantLib } from "../../../web-util/lib/context/activity.js";
 
 /**
  * Has the information to reach and
  * authenticate at the bank's backend.
  */
-export type SessionState = LoggedIn | LoggedOut | Expired;
+export type SessionState = LoggedIn | LoggedOut;
 
 interface LoggedIn {
   status: "loggedIn";
+
+  // is this instance admin? usually "default" name
   isAdmin: boolean;
+
+  // url where all the request will be made
+  // usually this is from where the SPA was loaded
+  // unless it's using impersonate feature
+  backendUrl: URL;
+
+  // instance name
   instance: string;
+
+  // session is not the same from where it was loaded
+  impersonated: boolean;
+
+  //instane access token
   token: AccessToken | undefined;
-  impersonate: Impersonate | undefined;
-}
-interface Impersonate {
-  originalInstance: string;
-  originalToken: AccessToken | undefined;
-  originalBackendUrl: string;
-}
-interface Expired {
-  status: "expired";
-  isAdmin: boolean;
-  instance: string;
-  token?: undefined;
-  impersonate: Impersonate | undefined;
 }
+
 interface LoggedOut {
   status: "loggedOut";
+  backendUrl: URL;
   instance: string;
   isAdmin: boolean;
-  token?: undefined;
+  token: AccessToken | undefined;
 }
 
-export const codecForSessionStateLoggedIn = (): Codec<LoggedIn> =>
-  buildCodecForObject<LoggedIn>()
-    .property("status", codecForConstString("loggedIn"))
-    .property("instance", codecForString())
-    .property("impersonate", codecOptional(codecForImpresonate()))
+interface SavedSession {
+  backendUrl: URL;
+  token: AccessToken | undefined;
+  prevToken: AccessToken | undefined;
+}
+
+export const codecForSessionState = (): Codec<SavedSession> =>
+  buildCodecForObject<SavedSession>()
+    .property("backendUrl", codecForURL())
     .property("token", codecOptional(codecForString() as Codec<AccessToken>))
-    .property("isAdmin", codecForBoolean())
-    .build("SessionState.LoggedIn");
-
-export const codecForSessionStateExpired = (): Codec<Expired> =>
-  buildCodecForObject<Expired>()
-    .property("status", codecForConstString("expired"))
-    .property("instance", codecForString())
-    .property("impersonate", codecOptional(codecForImpresonate()))
-    .property("isAdmin", codecForBoolean())
-    .build("SessionState.Expired");
-
-export const codecForSessionStateLoggedOut = (): Codec<LoggedOut> =>
-  buildCodecForObject<LoggedOut>()
-    .property("status", codecForConstString("loggedOut"))
-    .property("instance", codecForString())
-    .property("isAdmin", codecForBoolean())
-    .build("SessionState.LoggedOut");
-
-export const codecForImpresonate = (): Codec<Impersonate> =>
-  buildCodecForObject<Impersonate>()
-    .property("originalInstance", codecForString())
     .property(
-      "originalToken",
+      "prevToken",
       codecOptional(codecForString() as Codec<AccessToken>),
     )
-    .property("originalBackendUrl", codecForString())
-    .build("SessionState.Impersonate");
-
-export const codecForSessionState = (): Codec<SessionState> =>
-  buildCodecForUnion<SessionState>()
-    .discriminateOn("status")
-    .alternative("loggedIn", codecForSessionStateLoggedIn())
-    .alternative("loggedOut", codecForSessionStateLoggedOut())
-    .alternative("expired", codecForSessionStateExpired())
-    .build("SessionState");
+    .build("SavedSession");
 
 function inferInstanceName(url: URL) {
   const match = INSTANCE_ID_LOOKUP.exec(url.href);
   return !match || !match[1] ? DEFAULT_ADMIN_USERNAME : match[1];
 }
 
-export const defaultState = (url: URL): SessionState => {
-  const instance = inferInstanceName(url);
+export const defaultState = (url: URL): SavedSession => {
   return {
-    status: "loggedIn",
-    instance,
-    isAdmin: instance === DEFAULT_ADMIN_USERNAME,
+    backendUrl: url,
     token: undefined,
-    impersonate: undefined,
+    prevToken: undefined,
   };
 };
 
 export interface SessionStateHandler {
+  lib: MerchantLib;
+  config: TalerMerchantApi.VersionResponse;
+
   state: SessionState;
   /**
    * from every state to logout state
@@ -131,20 +110,16 @@ export interface SessionStateHandler {
    * from impersonate to loggedIn
    */
   deImpersonate(): void;
-  /**
-   * from non-loggedOut state to expired
-   */
-  expired(): void;
   /**
    * from any to loggedIn
    * @param info
    */
-  logIn(info: { token?: AccessToken }): void;
+  logIn(token: AccessToken | undefined): void;
   /**
    * from loggedIn to impersonate
    * @param info
    */
-  impersonate(info: { instance: string; baseUrl: URL, token?: AccessToken }): 
void;
+  impersonate(baseUrl: URL): void;
 }
 
 const SESSION_STATE_KEY = buildStorageKey(
@@ -156,95 +131,116 @@ export const DEFAULT_ADMIN_USERNAME = "default";
 
 export const INSTANCE_ID_LOOKUP = /\/instances\/([^/]*)\/?$/;
 
-/**
- * Return getters and setters for
- * login credentials and backend's
- * base URL.
- */
-export function useSessionContext(): SessionStateHandler {
-  const { url: merchantUrl, changeBackend } = useMerchantApiContext();
+export function cleanAllCache(): void {
+  mutate(() => true, undefined, { revalidate: false });
+}
 
+const Context = createContext<SessionStateHandler>(undefined!);
+
+export const useSessionContext = (): SessionStateHandler => 
useContext(Context);
+
+export const SessionContextProvider = ({
+  children,
+  // value,
+}: {
+  // value: MerchantUiSettings;
+  children: ComponentChildren;
+}): VNode => {
+  const {
+    lib: rootLib,
+    config: rootConfig,
+    url: merchantUrl,
+  } = useMerchantApiContext();
+  const [status, setStatus] = useState<"loggedIn" | "loggedOut">("loggedIn");
+  const [currentConfig, setCurrentConfig] =
+    useState<TalerMerchantApi.VersionResponse>();
   const { value: state, update } = useLocalStorage(
     SESSION_STATE_KEY,
     defaultState(merchantUrl),
   );
 
-  return {
-    state,
+  const currentInstance = inferInstanceName(state.backendUrl);
+
+  let lib: MerchantLib;
+  let config: TalerMerchantApi.VersionResponse;
+  const doingImpersonation = state.backendUrl.href !== merchantUrl.href;
+  if (doingImpersonation) {
+    /**
+     * FIXME: can't impersonate other than local instances
+     */
+    lib = rootLib.subInstanceApi(inferInstanceName(state.backendUrl));
+
+    config = currentConfig ?? rootConfig;
+  } else {
+    lib = rootLib;
+    config = rootConfig;
+  }
+
+  useEffect(() => {
+    // FIXME: handle what happen if the subinstance /config
+    // fails
+    if (!doingImpersonation) return;
+    lib.instance.getConfig().then((resp) => {
+      if (resp.type === "ok") {
+        setCurrentConfig(resp.body);
+      }
+    });
+  }, [state.backendUrl.href]);
+
+  const value: SessionStateHandler = {
+    state: {
+      backendUrl: state.backendUrl,
+      token: state.token,
+      impersonated: doingImpersonation,
+      instance: currentInstance,
+      isAdmin: currentInstance === DEFAULT_ADMIN_USERNAME,
+      status: status,
+    },
+    lib,
+    config,
     logOut() {
-      const instance = inferInstanceName(merchantUrl);
-      const nextState: SessionState = {
-        status: "loggedOut",
-        instance,
-        isAdmin: instance === DEFAULT_ADMIN_USERNAME,
-      };
-      update(nextState);
+      setStatus("loggedOut");
+      update({
+        backendUrl: merchantUrl,
+        token: undefined,
+        prevToken: undefined,
+      });
+      cleanAllCache();
     },
     deImpersonate() {
-      if (state.status === "loggedOut" || state.status === "expired") {
-        // can't impersonate if not loggedin
-        return;
-      }
-      if (state.impersonate === undefined) {
-        return;
-      }
-      const newURL = new URL(`./`, state.impersonate.originalBackendUrl);
-      changeBackend(newURL);
-      const nextState: SessionState = {
-        status: "loggedIn",
-        isAdmin: state.impersonate.originalInstance === DEFAULT_ADMIN_USERNAME,
-        instance: state.impersonate.originalInstance,
-        token: state.impersonate.originalToken,
-        impersonate: undefined,
-      };
-      update(nextState);
-    },
-    impersonate(info) {
-      if (state.status === "loggedOut" || state.status === "expired") {
-        // can't impersonate if not loggedin
-        return;
-      }
-      changeBackend(info.baseUrl);
-      const nextState: SessionState = {
-        status: "loggedIn",
-        isAdmin: info.instance === DEFAULT_ADMIN_USERNAME,
-        instance: info.instance,
-        // FIXME: bank and merchant should have consistent behavior
-        token: info.token?.substring("secret-token:".length) as AccessToken,
-        impersonate: {
-          originalBackendUrl: merchantUrl.href,
-          originalToken: state.token,
-          originalInstance: state.instance,
-        },
-      };
-      update(nextState);
+      cleanAllCache();
+      update({
+        backendUrl: merchantUrl,
+        token: state.prevToken,
+        prevToken: undefined,
+      });
+      setStatus("loggedIn");
     },
-    expired() {
-      if (state.status === "loggedOut") return;
-
-      const nextState: SessionState = {
-        ...state,
-        status: "expired",
+    impersonate(baseUrl) {
+      /**
+       * FIXME: can't impersonate other than local instances
+       */
+      update({
+        backendUrl: baseUrl,
         token: undefined,
-      };
-      update(nextState);
+        prevToken: state.token,
+      });
+      setStatus("loggedIn");
+      cleanAllCache();
     },
-    logIn(info) {
-      // admin is defined by the username
-      const nextState: SessionState = {
-        impersonate: undefined,
-        ...state,
-        status: "loggedIn",
-        // FIXME: bank and merchant should have consistent behavior
-        token: info.token?.substring("secret-token:".length) as AccessToken,
-        // token: info.token,
-      };
-      update(nextState);
+    logIn(token) {
       cleanAllCache();
+      setStatus("loggedIn");
+      update({
+        backendUrl: state.backendUrl,
+        token: token,
+        prevToken: state.prevToken,
+      });
     },
   };
-}
 
-export function cleanAllCache(): void {
-  mutate(() => true, undefined, { revalidate: false });
-}
+  return h(Context.Provider, {
+    value,
+    children,
+  });
+};
diff --git a/packages/merchant-backoffice-ui/src/hooks/bank.ts 
b/packages/merchant-backoffice-ui/src/hooks/bank.ts
index abfaecf68..8857ad839 100644
--- a/packages/merchant-backoffice-ui/src/hooks/bank.ts
+++ b/packages/merchant-backoffice-ui/src/hooks/bank.ts
@@ -16,14 +16,11 @@
 import {
   useMerchantApiContext
 } from "@gnu-taler/web-util/browser";
-import { useState } from "preact/hooks";
 
 // FIX default import https://github.com/microsoft/TypeScript/issues/49189
 import { AccessToken, TalerHttpError, TalerMerchantManagementResultByMethod } 
from "@gnu-taler/taler-util";
 import _useSWR, { SWRHook, mutate } from "swr";
 import { useSessionContext } from "../context/session.js";
-import { PAGINATED_LIST_REQUEST } from "../utils/constants.js";
-import { buildPaginatedResult } from "./webhooks.js";
 const useSWR = _useSWR as unknown as SWRHook;
 
 export interface InstanceBankAccountFilter {
@@ -38,11 +35,11 @@ export function revalidateInstanceBankAccounts() {
 }
 export function useInstanceBankAccounts() {
   const { state: session } = useSessionContext();
-  const { lib: { instance } } = useMerchantApiContext();
+  const { lib: { instance } } = useSessionContext();
 
   // const [offset, setOffset] = useState<string | undefined>();
 
-  async function fetcher([token, bid]: [AccessToken, string]) {
+  async function fetcher([token, _bid]: [AccessToken, string]) {
     return await instance.listBankAccounts(token, {
       // limit: PAGINATED_LIST_REQUEST,
       // offset: bid,
@@ -72,7 +69,7 @@ export function revalidateBankAccountDetails() {
 }
 export function useBankAccountDetails(h_wire: string) {
   const { state: session } = useSessionContext();
-  const { lib: { instance } } = useMerchantApiContext();
+  const { lib: { instance } } = useSessionContext();
 
   async function fetcher([token, wireId]: [AccessToken, string]) {
     return await instance.getBankAccountDetails(token, wireId);
diff --git a/packages/merchant-backoffice-ui/src/hooks/instance.ts 
b/packages/merchant-backoffice-ui/src/hooks/instance.ts
index 1fa84c9d9..f5f8893cd 100644
--- a/packages/merchant-backoffice-ui/src/hooks/instance.ts
+++ b/packages/merchant-backoffice-ui/src/hooks/instance.ts
@@ -13,9 +13,6 @@
  You should have received a copy of the GNU General Public License along with
  GNU Taler; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
  */
-import {
-  useMerchantApiContext
-} from "@gnu-taler/web-util/browser";
 
 // FIX default import https://github.com/microsoft/TypeScript/issues/49189
 import { AccessToken, TalerHttpError, TalerMerchantManagementResultByMethod } 
from "@gnu-taler/taler-util";
@@ -33,7 +30,7 @@ export function revalidateInstanceDetails() {
 }
 export function useInstanceDetails() {
   const { state: session } = useSessionContext();
-  const { lib: { instance } } = useMerchantApiContext();
+  const { lib: { instance } } = useSessionContext();
 
   async function fetcher([token]: [AccessToken]) {
     return await instance.getCurrentInstanceDetails(token);
@@ -58,7 +55,7 @@ export function revalidateInstanceKYCDetails() {
 }
 export function useInstanceKYCDetails() {
   const { state: session } = useSessionContext();
-  const { lib: { instance } } = useMerchantApiContext();
+  const { lib: { instance } } = useSessionContext();
 
   async function fetcher([token]: [AccessToken]) {
     return await instance.getCurrentIntanceKycStatus(token, {});
@@ -85,7 +82,7 @@ export function revalidateManagedInstanceDetails() {
 }
 export function useManagedInstanceDetails(instanceId: string) {
   const { state: session } = useSessionContext();
-  const { lib: { instance } } = useMerchantApiContext();
+  const { lib: { instance } } = useSessionContext();
 
   async function fetcher([token, instanceId]: [AccessToken, string]) {
     return await instance.getInstanceDetails(token, instanceId);
@@ -110,7 +107,7 @@ export function revalidateBackendInstances() {
 }
 export function useBackendInstances() {
   const { state: session } = useSessionContext();
-  const { lib: { instance } } = useMerchantApiContext();
+  const { lib: { instance } } = useSessionContext();
 
   async function fetcher([token]: [AccessToken]) {
     return await instance.listInstances(token);
diff --git a/packages/merchant-backoffice-ui/src/hooks/order.ts 
b/packages/merchant-backoffice-ui/src/hooks/order.ts
index 79f970ec2..d0513dc40 100644
--- a/packages/merchant-backoffice-ui/src/hooks/order.ts
+++ b/packages/merchant-backoffice-ui/src/hooks/order.ts
@@ -13,9 +13,6 @@
  You should have received a copy of the GNU General Public License along with
  GNU Taler; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
  */
-import {
-  useMerchantApiContext
-} from "@gnu-taler/web-util/browser";
 import { PAGINATED_LIST_REQUEST } from "../utils/constants.js";
 
 // FIX default import https://github.com/microsoft/TypeScript/issues/49189
@@ -36,7 +33,7 @@ export function revalidateOrderDetails() {
 }
 export function useOrderDetails(oderId: string) {
   const { state: session } = useSessionContext();
-  const { lib: { instance } } = useMerchantApiContext();
+  const { lib: { instance } } = useSessionContext();
 
   async function fetcher([dId, token]: [string, AccessToken]) {
     return await instance.getOrderDetails(token, dId);
@@ -72,7 +69,7 @@ export function useInstanceOrders(
   updatePosition: (d: string | undefined) => void = () => { },
 ) {
   const { state: session } = useSessionContext();
-  const { lib: { instance } } = useMerchantApiContext();
+  const { lib: { instance } } = useSessionContext();
 
   // const [offset, setOffset] = useState<string | undefined>(args?.position);
 
diff --git a/packages/merchant-backoffice-ui/src/hooks/otp.ts 
b/packages/merchant-backoffice-ui/src/hooks/otp.ts
index 8438a46b3..41ed89f70 100644
--- a/packages/merchant-backoffice-ui/src/hooks/otp.ts
+++ b/packages/merchant-backoffice-ui/src/hooks/otp.ts
@@ -13,9 +13,6 @@
  You should have received a copy of the GNU General Public License along with
  GNU Taler; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
  */
-import {
-  useMerchantApiContext
-} from "@gnu-taler/web-util/browser";
 
 // FIX default import https://github.com/microsoft/TypeScript/issues/49189
 import { AccessToken, TalerHttpError, TalerMerchantManagementResultByMethod } 
from "@gnu-taler/taler-util";
@@ -32,11 +29,11 @@ export function revalidateInstanceOtpDevices() {
 }
 export function useInstanceOtpDevices() {
   const { state: session } = useSessionContext();
-  const { lib: { instance } } = useMerchantApiContext();
+  const { lib: { instance } } = useSessionContext();
 
   // const [offset, setOffset] = useState<string | undefined>();
 
-  async function fetcher([token, bid]: [AccessToken, string]) {
+  async function fetcher([token, _bid]: [AccessToken, string]) {
     return await instance.listOtpDevices(token, {
       // limit: PAGINATED_LIST_REQUEST,
       // offset: bid,
@@ -66,7 +63,7 @@ export function revalidateOtpDeviceDetails() {
 }
 export function useOtpDeviceDetails(deviceId: string) {
   const { state: session } = useSessionContext();
-  const { lib: { instance } } = useMerchantApiContext();
+  const { lib: { instance } } = useSessionContext();
 
   async function fetcher([dId, token]: [string, AccessToken]) {
     return await instance.getOtpDeviceDetails(token, dId);
diff --git a/packages/merchant-backoffice-ui/src/hooks/product.ts 
b/packages/merchant-backoffice-ui/src/hooks/product.ts
index 7f3504c64..defda5552 100644
--- a/packages/merchant-backoffice-ui/src/hooks/product.ts
+++ b/packages/merchant-backoffice-ui/src/hooks/product.ts
@@ -13,9 +13,6 @@
  You should have received a copy of the GNU General Public License along with
  GNU Taler; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
  */
-import {
-  useMerchantApiContext
-} from "@gnu-taler/web-util/browser";
 
 // FIX default import https://github.com/microsoft/TypeScript/issues/49189
 import { AccessToken, OperationOk, TalerHttpError, TalerMerchantApi, 
TalerMerchantManagementErrorsByMethod, TalerMerchantManagementResultByMethod, 
opFixedSuccess } from "@gnu-taler/taler-util";
@@ -40,7 +37,7 @@ export function revalidateInstanceProducts() {
 }
 export function useInstanceProducts() {
   const { state: session } = useSessionContext();
-  const { lib: { instance } } = useMerchantApiContext();
+  const { lib: { instance } } = useSessionContext();
 
   const [offset, setOffset] = useState<number | undefined>();
 
@@ -89,7 +86,7 @@ export function revalidateProductDetails() {
 }
 export function useProductDetails(productId: string) {
   const { state: session } = useSessionContext();
-  const { lib: { instance } } = useMerchantApiContext();
+  const { lib: { instance } } = useSessionContext();
 
   async function fetcher([pid, token]: [string, AccessToken]) {
     return await instance.getProductDetails(token, pid);
diff --git a/packages/merchant-backoffice-ui/src/hooks/templates.ts 
b/packages/merchant-backoffice-ui/src/hooks/templates.ts
index e0065e284..12d99f3fc 100644
--- a/packages/merchant-backoffice-ui/src/hooks/templates.ts
+++ b/packages/merchant-backoffice-ui/src/hooks/templates.ts
@@ -13,9 +13,6 @@
  You should have received a copy of the GNU General Public License along with
  GNU Taler; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
  */
-import {
-  useMerchantApiContext
-} from "@gnu-taler/web-util/browser";
 import { useState } from "preact/hooks";
 import { PAGINATED_LIST_REQUEST } from "../utils/constants.js";
 
@@ -39,7 +36,7 @@ export function revalidateInstanceTemplates() {
 }
 export function useInstanceTemplates() {
   const { state: session } = useSessionContext();
-  const { lib: { instance } } = useMerchantApiContext();
+  const { lib: { instance } } = useSessionContext();
 
   const [offset, setOffset] = useState<string | undefined>();
 
@@ -73,7 +70,7 @@ export function revalidateTemplateDetails() {
 }
 export function useTemplateDetails(templateId: string) {
   const { state: session } = useSessionContext();
-  const { lib: { instance } } = useMerchantApiContext();
+  const { lib: { instance } } = useSessionContext();
 
   async function fetcher([tid, token]: [string, AccessToken]) {
     return await instance.getTemplateDetails(token, tid);
diff --git a/packages/merchant-backoffice-ui/src/hooks/transfer.ts 
b/packages/merchant-backoffice-ui/src/hooks/transfer.ts
index 6c2fc1d75..6f77369c2 100644
--- a/packages/merchant-backoffice-ui/src/hooks/transfer.ts
+++ b/packages/merchant-backoffice-ui/src/hooks/transfer.ts
@@ -13,9 +13,6 @@
  You should have received a copy of the GNU General Public License along with
  GNU Taler; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
  */
-import {
-  useMerchantApiContext
-} from "@gnu-taler/web-util/browser";
 import { PAGINATED_LIST_REQUEST } from "../utils/constants.js";
 
 // FIX default import https://github.com/microsoft/TypeScript/issues/49189
@@ -43,7 +40,7 @@ export function useInstanceTransfers(
   updatePosition: (id: string | undefined) => void = (() => { }),
 ) {
   const { state: session } = useSessionContext();
-  const { lib: { instance } } = useMerchantApiContext();
+  const { lib: { instance } } = useSessionContext();
 
   // const [offset, setOffset] = useState<string | undefined>(args?.position);
 
diff --git a/packages/merchant-backoffice-ui/src/hooks/webhooks.ts 
b/packages/merchant-backoffice-ui/src/hooks/webhooks.ts
index df53c06bc..fe37162aa 100644
--- a/packages/merchant-backoffice-ui/src/hooks/webhooks.ts
+++ b/packages/merchant-backoffice-ui/src/hooks/webhooks.ts
@@ -13,9 +13,6 @@
  You should have received a copy of the GNU General Public License along with
  GNU Taler; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
  */
-import {
-  useMerchantApiContext
-} from "@gnu-taler/web-util/browser";
 import { PAGINATED_LIST_REQUEST } from "../utils/constants.js";
 
 // FIX default import https://github.com/microsoft/TypeScript/issues/49189
@@ -36,11 +33,11 @@ export function revalidateInstanceWebhooks() {
 }
 export function useInstanceWebhooks() {
   const { state: session } = useSessionContext();
-  const { lib: { instance } } = useMerchantApiContext();
+  const { lib: { instance } } = useSessionContext();
 
   // const [offset, setOffset] = useState<string | undefined>();
 
-  async function fetcher([token, bid]: [AccessToken, string]) {
+  async function fetcher([token, _bid]: [AccessToken, string]) {
     return await instance.listWebhooks(token, {
       // limit: PAGINATED_LIST_REQUEST,
       // offset: bid,
@@ -104,7 +101,7 @@ export function revalidateWebhookDetails() {
 }
 export function useWebhookDetails(webhookId: string) {
   const { state: session } = useSessionContext();
-  const { lib: { instance } } = useMerchantApiContext();
+  const { lib: { instance } } = useSessionContext();
 
   async function fetcher([hookId, token]: [string, AccessToken]) {
     return await instance.getWebhookDetails(token, hookId);
diff --git 
a/packages/merchant-backoffice-ui/src/paths/admin/create/CreatePage.tsx 
b/packages/merchant-backoffice-ui/src/paths/admin/create/CreatePage.tsx
index 731ea8939..4a5ab440b 100644
--- a/packages/merchant-backoffice-ui/src/paths/admin/create/CreatePage.tsx
+++ b/packages/merchant-backoffice-ui/src/paths/admin/create/CreatePage.tsx
@@ -19,7 +19,11 @@
  * @author Sebastian Javier Marchano (sebasjm)
  */
 
-import { Duration, TalerMerchantApi } from "@gnu-taler/taler-util";
+import {
+  Duration,
+  TalerMerchantApi,
+  createAccessToken,
+} from "@gnu-taler/taler-util";
 import { useTranslationContext } from "@gnu-taler/web-util/browser";
 import { h, VNode } from "preact";
 import { useState } from "preact/hooks";
@@ -33,10 +37,13 @@ import { SetTokenNewInstanceModal } from 
"../../../components/modal/index.js";
 import { INSTANCE_ID_REGEX } from "../../../utils/constants.js";
 import { undefinedIfEmpty } from "../../../utils/table.js";
 
-export type Entity = Omit<Omit<TalerMerchantApi.InstanceConfigurationMessage, 
"default_pay_delay">, "default_wire_transfer_delay"> & {
+export type Entity = Omit<
+  Omit<TalerMerchantApi.InstanceConfigurationMessage, "default_pay_delay">,
+  "default_wire_transfer_delay"
+> & {
   auth_token?: string;
-  default_pay_delay: Duration,
-  default_wire_transfer_delay: Duration,
+  default_pay_delay: Duration;
+  default_wire_transfer_delay: Duration;
 };
 
 interface Props {
@@ -90,10 +97,11 @@ export function CreatePage({ onCreate, onBack, forceId }: 
Props): VNode {
     default_pay_delay: !value.default_pay_delay
       ? i18n.str`required`
       : !!value.default_wire_transfer_delay &&
-        value.default_wire_transfer_delay.d_ms !== "forever" &&
-        value.default_pay_delay.d_ms !== "forever" &&
-        value.default_pay_delay.d_ms > value.default_wire_transfer_delay.d_ms ?
-        i18n.str`pay delay can't be greater than wire transfer delay` : 
undefined,
+          value.default_wire_transfer_delay.d_ms !== "forever" &&
+          value.default_pay_delay.d_ms !== "forever" &&
+          value.default_pay_delay.d_ms > value.default_wire_transfer_delay.d_ms
+        ? i18n.str`pay delay can't be greater than wire transfer delay`
+        : undefined,
     default_wire_transfer_delay: !value.default_wire_transfer_delay
       ? i18n.str`required`
       : undefined,
@@ -112,7 +120,7 @@ export function CreatePage({ onCreate, onBack, forceId }: 
Props): VNode {
   };
 
   const hasErrors = Object.keys(errors).some(
-    (k) => (errors as any)[k] !== undefined,
+    (k) => (errors as Record<string, unknown>)[k] !== undefined,
   );
 
   const submit = (): Promise<void> => {
@@ -121,19 +129,26 @@ export function CreatePage({ onCreate, onBack, forceId }: 
Props): VNode {
 
     const newToken = newValue.auth_token;
     newValue.auth_token = undefined;
-    newValue.auth = newToken === null || newToken === undefined
-      ? { method: "external" }
-      : { method: "token", token: `secret-token:${newToken}` };
+    newValue.auth =
+      newToken === null || newToken === undefined
+        ? { method: "external" }
+        : { method: "token", token: createAccessToken(newToken) };
     if (!newValue.address) newValue.address = {};
     if (!newValue.jurisdiction) newValue.jurisdiction = {};
     // remove above use conversion
     // schema.validateSync(value, { abortEarly: false })
-    newValue.default_pay_delay = 
Duration.toTalerProtocolDuration(newValue.default_pay_delay!) as any
-    newValue.default_wire_transfer_delay = 
Duration.toTalerProtocolDuration(newValue.default_wire_transfer_delay!) as any
+    newValue.default_pay_delay = Duration.toTalerProtocolDuration(
+      newValue.default_pay_delay!,
+    ) as any;
+    newValue.default_wire_transfer_delay = Duration.toTalerProtocolDuration(
+      newValue.default_wire_transfer_delay!,
+    ) as any;
     // delete value.default_pay_delay;
     // delete value.default_wire_transfer_delay;
 
-    return onCreate(newValue as any as 
TalerMerchantApi.InstanceConfigurationMessage);
+    return onCreate(
+      newValue as any as TalerMerchantApi.InstanceConfigurationMessage,
+    );
   };
 
   function updateToken(token: string | null) {
diff --git a/packages/merchant-backoffice-ui/src/paths/admin/create/index.tsx 
b/packages/merchant-backoffice-ui/src/paths/admin/create/index.tsx
index 8ee8608a3..b00cfbe7d 100644
--- a/packages/merchant-backoffice-ui/src/paths/admin/create/index.tsx
+++ b/packages/merchant-backoffice-ui/src/paths/admin/create/index.tsx
@@ -19,8 +19,7 @@
  */
 import { TalerMerchantApi } from "@gnu-taler/taler-util";
 import {
-  useMerchantApiContext,
-  useTranslationContext,
+  useTranslationContext
 } from "@gnu-taler/web-util/browser";
 import { Fragment, VNode, h } from "preact";
 import { useState } from "preact/hooks";
@@ -39,7 +38,7 @@ export type Entity = 
TalerMerchantApi.InstanceConfigurationMessage;
 export default function Create({ onBack, onConfirm, forceId }: Props): VNode {
   const [notif, setNotif] = useState<Notification | undefined>(undefined);
   const { i18n } = useTranslationContext();
-  const { lib } = useMerchantApiContext();
+  const { lib } = useSessionContext();
   const { state, logIn } = useSessionContext();
 
   return (
@@ -69,7 +68,7 @@ export default function Create({ onBack, onConfirm, forceId 
}: Props): VNode {
               );
               if (result.type === "ok") {
                 const { token } = result.body;
-                logIn({ token });
+                logIn(token);
               }
             }
             onConfirm();
diff --git 
a/packages/merchant-backoffice-ui/src/paths/admin/list/TableActive.tsx 
b/packages/merchant-backoffice-ui/src/paths/admin/list/TableActive.tsx
index b246bb3e2..cff3c5a02 100644
--- a/packages/merchant-backoffice-ui/src/paths/admin/list/TableActive.tsx
+++ b/packages/merchant-backoffice-ui/src/paths/admin/list/TableActive.tsx
@@ -21,7 +21,6 @@
 
 import { TalerMerchantApi } from "@gnu-taler/taler-util";
 import {
-  useMerchantApiContext,
   useTranslationContext
 } from "@gnu-taler/web-util/browser";
 import { VNode, h } from "preact";
@@ -152,7 +151,7 @@ function Table({
   onPurge,
 }: TableProps): VNode {
   const { i18n } = useTranslationContext();
-  const { lib } = useMerchantApiContext();
+  const { lib } = useSessionContext();
   const { impersonate } = useSessionContext();
   return (
     <div class="table-container">
@@ -203,15 +202,11 @@ function Table({
                 <td>
                   <a
                     href={`#/orders`}
-                    onClick={async (e) => {
-                      e.preventDefault();
+                    onClick={async (_e) => {
+                      // e.preventDefault();
                       const newInstanceApi = lib.subInstanceApi(i.id);
                       //not checking /config since this comes from instance 
list
-                      impersonate({
-                        instance: i.id,
-                        baseUrl: new URL(newInstanceApi.instance.baseUrl),
-                        token: undefined,
-                      });
+                      impersonate(new URL(newInstanceApi.instance.baseUrl));
                     }}
                   >
                     {i.id}
diff --git a/packages/merchant-backoffice-ui/src/paths/admin/list/index.tsx 
b/packages/merchant-backoffice-ui/src/paths/admin/list/index.tsx
index 7bf64cdbb..5b492e45c 100644
--- a/packages/merchant-backoffice-ui/src/paths/admin/list/index.tsx
+++ b/packages/merchant-backoffice-ui/src/paths/admin/list/index.tsx
@@ -21,7 +21,6 @@
 
 import { HttpStatusCode, TalerError, TalerMerchantApi, assertUnreachable } 
from "@gnu-taler/taler-util";
 import {
-  useMerchantApiContext,
   useTranslationContext
 } from "@gnu-taler/web-util/browser";
 import { Fragment, VNode, h } from "preact";
@@ -33,8 +32,8 @@ import { DeleteModal, PurgeModal } from 
"../../../components/modal/index.js";
 import { useSessionContext } from "../../../context/session.js";
 import { useBackendInstances } from "../../../hooks/instance.js";
 import { Notification } from "../../../utils/types.js";
-import { View } from "./View.js";
 import { LoginPage } from "../../login/index.js";
+import { View } from "./View.js";
 
 interface Props {
   onCreate: () => void;
@@ -53,7 +52,7 @@ export default function Instances({
     useState<TalerMerchantApi.Instance | null>(null);
   const [notif, setNotif] = useState<Notification | undefined>(undefined);
   const { i18n } = useTranslationContext();
-  const { lib } = useMerchantApiContext();
+  const { lib } = useSessionContext();
   const { state } = useSessionContext();
 
   if (!result) return <Loading />
diff --git 
a/packages/merchant-backoffice-ui/src/paths/instance/accounts/create/index.tsx 
b/packages/merchant-backoffice-ui/src/paths/instance/accounts/create/index.tsx
index fb50ab995..9bab33f6f 100644
--- 
a/packages/merchant-backoffice-ui/src/paths/instance/accounts/create/index.tsx
+++ 
b/packages/merchant-backoffice-ui/src/paths/instance/accounts/create/index.tsx
@@ -32,15 +32,14 @@ import {
 } from "@gnu-taler/taler-util";
 import {
   BrowserFetchHttpLib,
-  useMerchantApiContext,
-  useTranslationContext,
+  useTranslationContext
 } from "@gnu-taler/web-util/browser";
-import { Fragment, h, VNode } from "preact";
+import { Fragment, VNode, h } from "preact";
 import { useState } from "preact/hooks";
 import { NotificationCard } from "../../../../components/menu/index.js";
+import { useSessionContext } from "../../../../context/session.js";
 import { Notification } from "../../../../utils/types.js";
 import { CreatePage } from "./CreatePage.js";
-import { useSessionContext } from "../../../../context/session.js";
 
 export type Entity = TalerMerchantApi.AccountAddDetails;
 interface Props {
@@ -49,7 +48,7 @@ interface Props {
 }
 
 export default function CreateValidator({ onConfirm, onBack }: Props): VNode {
-  const { lib: api } = useMerchantApiContext();
+  const { lib: api } = useSessionContext();
   const { state } = useSessionContext();
   const [notif, setNotif] = useState<Notification | undefined>(undefined);
   const { i18n } = useTranslationContext();
diff --git 
a/packages/merchant-backoffice-ui/src/paths/instance/accounts/list/index.tsx 
b/packages/merchant-backoffice-ui/src/paths/instance/accounts/list/index.tsx
index 613cb9614..1eda7382d 100644
--- a/packages/merchant-backoffice-ui/src/paths/instance/accounts/list/index.tsx
+++ b/packages/merchant-backoffice-ui/src/paths/instance/accounts/list/index.tsx
@@ -21,7 +21,6 @@
 
 import { HttpStatusCode, TalerError, TalerMerchantApi, assertUnreachable } 
from "@gnu-taler/taler-util";
 import {
-  useMerchantApiContext,
   useTranslationContext
 } from "@gnu-taler/web-util/browser";
 import { Fragment, VNode, h } from "preact";
@@ -32,9 +31,9 @@ import { NotificationCard } from 
"../../../../components/menu/index.js";
 import { useSessionContext } from "../../../../context/session.js";
 import { useInstanceBankAccounts } from "../../../../hooks/bank.js";
 import { Notification } from "../../../../utils/types.js";
+import { LoginPage } from "../../../login/index.js";
 import { NotFoundPageOrAdminCreate } from "../../../notfound/index.js";
 import { ListPage } from "./ListPage.js";
-import { LoginPage } from "../../../login/index.js";
 
 interface Props {
   onCreate: () => void;
@@ -47,7 +46,7 @@ export default function ListOtpDevices({
 }: Props): VNode {
   const { i18n } = useTranslationContext();
   const [notif, setNotif] = useState<Notification | undefined>(undefined);
-  const { lib: api } = useMerchantApiContext();
+  const { lib: api } = useSessionContext();
   const { state } = useSessionContext();
   const result = useInstanceBankAccounts();
 
diff --git 
a/packages/merchant-backoffice-ui/src/paths/instance/accounts/update/index.tsx 
b/packages/merchant-backoffice-ui/src/paths/instance/accounts/update/index.tsx
index 519c9f56a..70942fd55 100644
--- 
a/packages/merchant-backoffice-ui/src/paths/instance/accounts/update/index.tsx
+++ 
b/packages/merchant-backoffice-ui/src/paths/instance/accounts/update/index.tsx
@@ -21,7 +21,6 @@
 
 import { HttpStatusCode, TalerError, TalerMerchantApi, assertUnreachable } 
from "@gnu-taler/taler-util";
 import {
-  useMerchantApiContext,
   useTranslationContext
 } from "@gnu-taler/web-util/browser";
 import { Fragment, VNode, h } from "preact";
@@ -34,8 +33,8 @@ import { useBankAccountDetails } from 
"../../../../hooks/bank.js";
 import { Notification } from "../../../../utils/types.js";
 import { LoginPage } from "../../../login/index.js";
 import { NotFoundPageOrAdminCreate } from "../../../notfound/index.js";
-import { UpdatePage } from "./UpdatePage.js";
 import { TestRevenueErrorType, testRevenueAPI } from "../create/index.js";
+import { UpdatePage } from "./UpdatePage.js";
 
 export type Entity = TalerMerchantApi.AccountPatchDetails & WithId;
 
@@ -49,7 +48,7 @@ export default function UpdateValidator({
   onConfirm,
   onBack,
 }: Props): VNode {
-  const { lib: api } = useMerchantApiContext();
+  const { lib: api } = useSessionContext();
   const { state } = useSessionContext();
   const result = useBankAccountDetails(bid);
   const [notif, setNotif] = useState<Notification | undefined>(undefined);
diff --git 
a/packages/merchant-backoffice-ui/src/paths/instance/details/index.tsx 
b/packages/merchant-backoffice-ui/src/paths/instance/details/index.tsx
index 76e3bf878..e1a7f87f0 100644
--- a/packages/merchant-backoffice-ui/src/paths/instance/details/index.tsx
+++ b/packages/merchant-backoffice-ui/src/paths/instance/details/index.tsx
@@ -14,7 +14,6 @@
  GNU Taler; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
  */
 import { HttpStatusCode, TalerError, assertUnreachable } from 
"@gnu-taler/taler-util";
-import { useMerchantApiContext } from "@gnu-taler/web-util/browser";
 import { Fragment, VNode, h } from "preact";
 import { useState } from "preact/hooks";
 import { ErrorLoadingMerchant } from 
"../../../components/ErrorLoadingMerchant.js";
@@ -23,8 +22,8 @@ import { DeleteModal } from 
"../../../components/modal/index.js";
 import { useSessionContext } from "../../../context/session.js";
 import { useInstanceDetails } from "../../../hooks/instance.js";
 import { LoginPage } from "../../login/index.js";
-import { DetailPage } from "./DetailPage.js";
 import { NotFoundPageOrAdminCreate } from "../../notfound/index.js";
+import { DetailPage } from "./DetailPage.js";
 
 interface Props {
   onUpdate: () => void;
@@ -40,7 +39,7 @@ export default function Detail({
   const [deleting, setDeleting] = useState<boolean>(false);
 
   // const { deleteInstance } = useInstanceAPI();
-  const { lib } = useMerchantApiContext();
+  const { lib } = useSessionContext();
 
   if (!result) return <Loading />
   if (result instanceof TalerError) {
diff --git 
a/packages/merchant-backoffice-ui/src/paths/instance/orders/create/CreatePage.tsx
 
b/packages/merchant-backoffice-ui/src/paths/instance/orders/create/CreatePage.tsx
index 041ec73e7..7be3d23f6 100644
--- 
a/packages/merchant-backoffice-ui/src/paths/instance/orders/create/CreatePage.tsx
+++ 
b/packages/merchant-backoffice-ui/src/paths/instance/orders/create/CreatePage.tsx
@@ -28,8 +28,7 @@ import {
   TalerProtocolDuration,
 } from "@gnu-taler/taler-util";
 import {
-  useMerchantApiContext,
-  useTranslationContext,
+  useTranslationContext
 } from "@gnu-taler/web-util/browser";
 import { format, isFuture } from "date-fns";
 import { Fragment, VNode, h } from "preact";
@@ -49,6 +48,7 @@ import { InputToggle } from 
"../../../../components/form/InputToggle.js";
 import { InventoryProductForm } from 
"../../../../components/product/InventoryProductForm.js";
 import { NonInventoryProductFrom } from 
"../../../../components/product/NonInventoryProductForm.js";
 import { ProductList } from "../../../../components/product/ProductList.js";
+import { useSessionContext } from "../../../../context/session.js";
 import { usePreference } from "../../../../hooks/preference.js";
 import { rate } from "../../../../utils/amount.js";
 import { undefinedIfEmpty } from "../../../../utils/table.js";
@@ -134,7 +134,7 @@ export function CreatePage({
   instanceConfig,
   instanceInventory,
 }: Props): VNode {
-  const { config } = useMerchantApiContext();
+  const { config } = useSessionContext();
   const instance_default = with_defaults(instanceConfig, config.currency);
   const [value, valueHandler] = useState(instance_default);
   const zero = Amounts.zeroOfCurrency(config.currency);
@@ -679,7 +679,6 @@ export function CreatePage({
                                 value.extra &&
                                 value.extra[key] !== undefined
                               ) {
-                                console.log(value.extra);
                                 delete value.extra[key];
                               }
                               valueHandler({
diff --git 
a/packages/merchant-backoffice-ui/src/paths/instance/orders/create/index.tsx 
b/packages/merchant-backoffice-ui/src/paths/instance/orders/create/index.tsx
index 849711df6..861114014 100644
--- a/packages/merchant-backoffice-ui/src/paths/instance/orders/create/index.tsx
+++ b/packages/merchant-backoffice-ui/src/paths/instance/orders/create/index.tsx
@@ -20,7 +20,6 @@
  */
 
 import { HttpStatusCode, TalerError, TalerMerchantApi, assertUnreachable } 
from "@gnu-taler/taler-util";
-import { useMerchantApiContext } from "@gnu-taler/web-util/browser";
 import { Fragment, VNode, h } from "preact";
 import { useState } from "preact/hooks";
 import { ErrorLoadingMerchant } from 
"../../../../components/ErrorLoadingMerchant.js";
@@ -30,9 +29,9 @@ import { useSessionContext } from 
"../../../../context/session.js";
 import { useInstanceDetails } from "../../../../hooks/instance.js";
 import { useInstanceProducts } from "../../../../hooks/product.js";
 import { Notification } from "../../../../utils/types.js";
-import { CreatePage } from "./CreatePage.js";
-import { NotFoundPageOrAdminCreate } from "../../../notfound/index.js";
 import { LoginPage } from "../../../login/index.js";
+import { NotFoundPageOrAdminCreate } from "../../../notfound/index.js";
+import { CreatePage } from "./CreatePage.js";
 
 export type Entity = {
   request: TalerMerchantApi.PostOrderRequest;
@@ -46,7 +45,7 @@ export default function OrderCreate({
   onConfirm,
   onBack,
 }: Props): VNode {
-  const { lib } = useMerchantApiContext();
+  const { lib } = useSessionContext();
   const [notif, setNotif] = useState<Notification | undefined>(undefined);
   const { state } = useSessionContext();
   const detailsResult = useInstanceDetails();
diff --git 
a/packages/merchant-backoffice-ui/src/paths/instance/orders/details/DetailPage.tsx
 
b/packages/merchant-backoffice-ui/src/paths/instance/orders/details/DetailPage.tsx
index 4aed0cc42..498ea83e3 100644
--- 
a/packages/merchant-backoffice-ui/src/paths/instance/orders/details/DetailPage.tsx
+++ 
b/packages/merchant-backoffice-ui/src/paths/instance/orders/details/DetailPage.tsx
@@ -26,8 +26,7 @@ import {
   stringifyRefundUri,
 } from "@gnu-taler/taler-util";
 import {
-  useMerchantApiContext,
-  useTranslationContext,
+  useTranslationContext
 } from "@gnu-taler/web-util/browser";
 import { format, formatDistance } from "date-fns";
 import { Fragment, VNode, h } from "preact";
@@ -41,6 +40,7 @@ import { InputGroup } from 
"../../../../components/form/InputGroup.js";
 import { InputLocation } from "../../../../components/form/InputLocation.js";
 import { TextField } from "../../../../components/form/TextField.js";
 import { ProductList } from "../../../../components/product/ProductList.js";
+import { useSessionContext } from "../../../../context/session.js";
 import {
   datetimeFormatForSettings,
   usePreference,
@@ -430,10 +430,10 @@ function PaidPage({
   });
 
   const [value, valueHandler] = useState<Partial<Paid>>(order);
-  const { url: backendUrl } = useMerchantApiContext();
+  const { state } = useSessionContext();
 
   const refundurl = stringifyRefundUri({
-    merchantBaseUrl: backendUrl.href,
+    merchantBaseUrl: state.backendUrl.href,
     orderId: order.contract_terms.order_id,
   });
   const { i18n } = useTranslationContext();
diff --git 
a/packages/merchant-backoffice-ui/src/paths/instance/orders/details/index.tsx 
b/packages/merchant-backoffice-ui/src/paths/instance/orders/details/index.tsx
index 4785c795d..b28e59b29 100644
--- 
a/packages/merchant-backoffice-ui/src/paths/instance/orders/details/index.tsx
+++ 
b/packages/merchant-backoffice-ui/src/paths/instance/orders/details/index.tsx
@@ -19,8 +19,7 @@ import {
   assertUnreachable,
 } from "@gnu-taler/taler-util";
 import {
-  useMerchantApiContext,
-  useTranslationContext,
+  useTranslationContext
 } from "@gnu-taler/web-util/browser";
 import { Fragment, VNode, h } from "preact";
 import { useState } from "preact/hooks";
@@ -30,9 +29,9 @@ import { NotificationCard } from 
"../../../../components/menu/index.js";
 import { useSessionContext } from "../../../../context/session.js";
 import { useOrderDetails } from "../../../../hooks/order.js";
 import { Notification } from "../../../../utils/types.js";
+import { LoginPage } from "../../../login/index.js";
 import { NotFoundPageOrAdminCreate } from "../../../notfound/index.js";
 import { DetailPage } from "./DetailPage.js";
-import { LoginPage } from "../../../login/index.js";
 
 export interface Props {
   oid: string;
@@ -42,7 +41,7 @@ export interface Props {
 export default function Update({ oid, onBack }: Props): VNode {
   const result = useOrderDetails(oid);
   const [notif, setNotif] = useState<Notification | undefined>(undefined);
-  const { lib: api } = useMerchantApiContext();
+  const { lib: api } = useSessionContext();
   const { state } = useSessionContext();
 
   const { i18n } = useTranslationContext();
diff --git 
a/packages/merchant-backoffice-ui/src/paths/instance/orders/list/Table.tsx 
b/packages/merchant-backoffice-ui/src/paths/instance/orders/list/Table.tsx
index a9314d005..5ece34409 100644
--- a/packages/merchant-backoffice-ui/src/paths/instance/orders/list/Table.tsx
+++ b/packages/merchant-backoffice-ui/src/paths/instance/orders/list/Table.tsx
@@ -21,8 +21,7 @@
 
 import { Amounts, TalerMerchantApi } from "@gnu-taler/taler-util";
 import {
-  useMerchantApiContext,
-  useTranslationContext,
+  useTranslationContext
 } from "@gnu-taler/web-util/browser";
 import { format } from "date-fns";
 import { VNode, h } from "preact";
@@ -36,6 +35,7 @@ import { InputCurrency } from 
"../../../../components/form/InputCurrency.js";
 import { InputGroup } from "../../../../components/form/InputGroup.js";
 import { InputSelector } from "../../../../components/form/InputSelector.js";
 import { ConfirmModal } from "../../../../components/modal/index.js";
+import { useSessionContext } from "../../../../context/session.js";
 import {
   datetimeFormatForSettings,
   usePreference,
@@ -258,7 +258,7 @@ export function RefundModal({
     order.order_status === "paid" ? order.refund_details : []
   ).reduce(mergeRefunds, []);
 
-  const { config } = useMerchantApiContext();
+  const { config } = useSessionContext();
   const totalRefunded = refunds
     .map((r) => r.amount)
     .reduce(
diff --git 
a/packages/merchant-backoffice-ui/src/paths/instance/orders/list/index.tsx 
b/packages/merchant-backoffice-ui/src/paths/instance/orders/list/index.tsx
index af1ffbcc6..8a1f85b1c 100644
--- a/packages/merchant-backoffice-ui/src/paths/instance/orders/list/index.tsx
+++ b/packages/merchant-backoffice-ui/src/paths/instance/orders/list/index.tsx
@@ -27,8 +27,7 @@ import {
   assertUnreachable,
 } from "@gnu-taler/taler-util";
 import {
-  useMerchantApiContext,
-  useTranslationContext,
+  useTranslationContext
 } from "@gnu-taler/web-util/browser";
 import { VNode, h } from "preact";
 import { useState } from "preact/hooks";
@@ -43,10 +42,10 @@ import {
   useOrderDetails,
 } from "../../../../hooks/order.js";
 import { Notification } from "../../../../utils/types.js";
+import { LoginPage } from "../../../login/index.js";
 import { NotFoundPageOrAdminCreate } from "../../../notfound/index.js";
 import { ListPage } from "./ListPage.js";
 import { RefundModal } from "./Table.js";
-import { LoginPage } from "../../../login/index.js";
 
 interface Props {
   onSelect: (id: string) => void;
@@ -65,7 +64,7 @@ export default function OrderList({ onCreate, onSelect }: 
Props): VNode {
   const result = useInstanceOrders(filter, (d) =>
     setFilter({ ...filter, position: d }),
   );
-  const { lib } = useMerchantApiContext();
+  const { lib } = useSessionContext();
 
   const [notif, setNotif] = useState<Notification | undefined>(undefined);
 
diff --git 
a/packages/merchant-backoffice-ui/src/paths/instance/otp_devices/create/CreatedSuccessfully.tsx
 
b/packages/merchant-backoffice-ui/src/paths/instance/otp_devices/create/CreatedSuccessfully.tsx
index 982132057..7723bec81 100644
--- 
a/packages/merchant-backoffice-ui/src/paths/instance/otp_devices/create/CreatedSuccessfully.tsx
+++ 
b/packages/merchant-backoffice-ui/src/paths/instance/otp_devices/create/CreatedSuccessfully.tsx
@@ -15,7 +15,7 @@
  */
 
 import { TalerMerchantApi } from "@gnu-taler/taler-util";
-import { useMerchantApiContext, useTranslationContext } from 
"@gnu-taler/web-util/browser";
+import { useTranslationContext } from "@gnu-taler/web-util/browser";
 import { VNode, h } from "preact";
 import { QR } from "../../../../components/exception/QR.js";
 import { CreatedSuccessfully as Template } from 
"../../../../components/notifications/CreatedSuccessfully.js";
@@ -33,9 +33,8 @@ export function CreatedSuccessfully({
   onConfirm,
 }: Props): VNode {
   const { i18n } = useTranslationContext();
-  const { url: backendUrl } = useMerchantApiContext();
   const { state } = useSessionContext();
-  const issuer = backendUrl.href;
+  const issuer = state.backendUrl.href;
   const qrText = 
`otpauth://totp/${state.instance}/${entity.otp_device_id}?issuer=${issuer}&algorithm=SHA1&digits=8&period=30&secret=${entity.otp_key}`;
   const qrTextSafe = 
`otpauth://totp/${state.instance}/${entity.otp_device_id}?issuer=${issuer}&algorithm=SHA1&digits=8&period=30&secret=${entity.otp_key.substring(0,
 6)}...`;
 
diff --git 
a/packages/merchant-backoffice-ui/src/paths/instance/otp_devices/create/index.tsx
 
b/packages/merchant-backoffice-ui/src/paths/instance/otp_devices/create/index.tsx
index 864190c9f..8ab0e1f26 100644
--- 
a/packages/merchant-backoffice-ui/src/paths/instance/otp_devices/create/index.tsx
+++ 
b/packages/merchant-backoffice-ui/src/paths/instance/otp_devices/create/index.tsx
@@ -20,14 +20,14 @@
  */
 
 import { TalerMerchantApi } from "@gnu-taler/taler-util";
-import { useMerchantApiContext, useTranslationContext } from 
"@gnu-taler/web-util/browser";
-import { Fragment, h, VNode } from "preact";
+import { useTranslationContext } from "@gnu-taler/web-util/browser";
+import { Fragment, VNode, h } from "preact";
 import { useState } from "preact/hooks";
 import { NotificationCard } from "../../../../components/menu/index.js";
+import { useSessionContext } from "../../../../context/session.js";
 import { Notification } from "../../../../utils/types.js";
-import { CreatedSuccessfully } from "./CreatedSuccessfully.js";
 import { CreatePage } from "./CreatePage.js";
-import { useSessionContext } from "../../../../context/session.js";
+import { CreatedSuccessfully } from "./CreatedSuccessfully.js";
 
 export type Entity = TalerMerchantApi.OtpDeviceAddDetails;
 interface Props {
@@ -36,7 +36,7 @@ interface Props {
 }
 
 export default function CreateValidator({ onConfirm, onBack }: Props): VNode {
-  const { lib: api } = useMerchantApiContext();
+  const { lib: api } = useSessionContext();
   const { state } = useSessionContext();
   const [notif, setNotif] = useState<Notification | undefined>(undefined);
   const { i18n } = useTranslationContext();
diff --git 
a/packages/merchant-backoffice-ui/src/paths/instance/otp_devices/list/index.tsx 
b/packages/merchant-backoffice-ui/src/paths/instance/otp_devices/list/index.tsx
index 776823a95..b6a077863 100644
--- 
a/packages/merchant-backoffice-ui/src/paths/instance/otp_devices/list/index.tsx
+++ 
b/packages/merchant-backoffice-ui/src/paths/instance/otp_devices/list/index.tsx
@@ -26,7 +26,6 @@ import {
   assertUnreachable
 } from "@gnu-taler/taler-util";
 import {
-  useMerchantApiContext,
   useTranslationContext
 } from "@gnu-taler/web-util/browser";
 import { Fragment, VNode, h } from "preact";
@@ -37,9 +36,9 @@ import { NotificationCard } from 
"../../../../components/menu/index.js";
 import { useSessionContext } from "../../../../context/session.js";
 import { useInstanceOtpDevices } from "../../../../hooks/otp.js";
 import { Notification } from "../../../../utils/types.js";
+import { LoginPage } from "../../../login/index.js";
 import { NotFoundPageOrAdminCreate } from "../../../notfound/index.js";
 import { ListPage } from "./ListPage.js";
-import { LoginPage } from "../../../login/index.js";
 
 interface Props {
   onCreate: () => void;
@@ -50,7 +49,7 @@ export default function ListOtpDevices({ onCreate, onSelect 
}: Props): VNode {
   // const [position, setPosition] = useState<string | undefined>(undefined);
   const { i18n } = useTranslationContext();
   const [notif, setNotif] = useState<Notification | undefined>(undefined);
-  const { lib } = useMerchantApiContext();
+  const { lib } = useSessionContext();
   const { state } = useSessionContext();
   const result = useInstanceOtpDevices();
 
diff --git 
a/packages/merchant-backoffice-ui/src/paths/instance/otp_devices/update/index.tsx
 
b/packages/merchant-backoffice-ui/src/paths/instance/otp_devices/update/index.tsx
index 5e34e4c8a..99edb95c3 100644
--- 
a/packages/merchant-backoffice-ui/src/paths/instance/otp_devices/update/index.tsx
+++ 
b/packages/merchant-backoffice-ui/src/paths/instance/otp_devices/update/index.tsx
@@ -26,7 +26,6 @@ import {
   assertUnreachable
 } from "@gnu-taler/taler-util";
 import {
-  useMerchantApiContext,
   useTranslationContext
 } from "@gnu-taler/web-util/browser";
 import { Fragment, VNode, h } from "preact";
@@ -37,10 +36,10 @@ import { NotificationCard } from 
"../../../../components/menu/index.js";
 import { useSessionContext } from "../../../../context/session.js";
 import { useOtpDeviceDetails } from "../../../../hooks/otp.js";
 import { Notification } from "../../../../utils/types.js";
+import { LoginPage } from "../../../login/index.js";
 import { NotFoundPageOrAdminCreate } from "../../../notfound/index.js";
 import { CreatedSuccessfully } from "../create/CreatedSuccessfully.js";
 import { UpdatePage } from "./UpdatePage.js";
-import { LoginPage } from "../../../login/index.js";
 
 export type Entity = TalerMerchantApi.OtpDevicePatchDetails & WithId;
 
@@ -58,7 +57,7 @@ export default function UpdateValidator({
   const [notif, setNotif] = useState<Notification | undefined>(undefined);
   const [keyUpdated, setKeyUpdated] =
     useState<TalerMerchantApi.OtpDeviceAddDetails | null>(null);
-  const { lib } = useMerchantApiContext();
+  const { lib } = useSessionContext();
   const { state } = useSessionContext();
 
   const { i18n } = useTranslationContext();
diff --git 
a/packages/merchant-backoffice-ui/src/paths/instance/products/create/index.tsx 
b/packages/merchant-backoffice-ui/src/paths/instance/products/create/index.tsx
index e1e3c846a..9de5cae78 100644
--- 
a/packages/merchant-backoffice-ui/src/paths/instance/products/create/index.tsx
+++ 
b/packages/merchant-backoffice-ui/src/paths/instance/products/create/index.tsx
@@ -20,13 +20,13 @@
  */
 
 import { TalerMerchantApi } from "@gnu-taler/taler-util";
-import { useMerchantApiContext, useTranslationContext } from 
"@gnu-taler/web-util/browser";
-import { Fragment, h, VNode } from "preact";
+import { useTranslationContext } from "@gnu-taler/web-util/browser";
+import { Fragment, VNode, h } from "preact";
 import { useState } from "preact/hooks";
 import { NotificationCard } from "../../../../components/menu/index.js";
+import { useSessionContext } from "../../../../context/session.js";
 import { Notification } from "../../../../utils/types.js";
 import { CreatePage } from "./CreatePage.js";
-import { useSessionContext } from "../../../../context/session.js";
 
 export type Entity = TalerMerchantApi.ProductAddDetail;
 interface Props {
@@ -34,7 +34,7 @@ interface Props {
   onConfirm: () => void;
 }
 export default function CreateProduct({ onConfirm, onBack }: Props): VNode {
-  const { lib } = useMerchantApiContext();
+  const { lib } = useSessionContext();
   const { state } = useSessionContext();
   const [notif, setNotif] = useState<Notification | undefined>(undefined);
   const { i18n } = useTranslationContext();
diff --git 
a/packages/merchant-backoffice-ui/src/paths/instance/products/list/index.tsx 
b/packages/merchant-backoffice-ui/src/paths/instance/products/list/index.tsx
index db6cf5376..6ad0d4598 100644
--- a/packages/merchant-backoffice-ui/src/paths/instance/products/list/index.tsx
+++ b/packages/merchant-backoffice-ui/src/paths/instance/products/list/index.tsx
@@ -21,7 +21,6 @@
 
 import { HttpStatusCode, TalerError, TalerMerchantApi, assertUnreachable } 
from "@gnu-taler/taler-util";
 import {
-  useMerchantApiContext,
   useTranslationContext
 } from "@gnu-taler/web-util/browser";
 import { VNode, h } from "preact";
@@ -36,9 +35,9 @@ import {
   useInstanceProducts
 } from "../../../../hooks/product.js";
 import { Notification } from "../../../../utils/types.js";
+import { LoginPage } from "../../../login/index.js";
 import { NotFoundPageOrAdminCreate } from "../../../notfound/index.js";
 import { CardTable } from "./Table.js";
-import { LoginPage } from "../../../login/index.js";
 
 interface Props {
   onCreate: () => void;
@@ -49,7 +48,7 @@ export default function ProductList({
   onSelect,
 }: Props): VNode {
   const result = useInstanceProducts();
-  const { lib } = useMerchantApiContext();
+  const { lib } = useSessionContext();
   const { state } = useSessionContext();
   const [deleting, setDeleting] =
     useState<TalerMerchantApi.ProductDetail & WithId | null>(null);
diff --git 
a/packages/merchant-backoffice-ui/src/paths/instance/products/update/index.tsx 
b/packages/merchant-backoffice-ui/src/paths/instance/products/update/index.tsx
index 06f813b14..5e3e58d80 100644
--- 
a/packages/merchant-backoffice-ui/src/paths/instance/products/update/index.tsx
+++ 
b/packages/merchant-backoffice-ui/src/paths/instance/products/update/index.tsx
@@ -21,7 +21,6 @@
 
 import { HttpStatusCode, TalerError, TalerMerchantApi, assertUnreachable } 
from "@gnu-taler/taler-util";
 import {
-  useMerchantApiContext,
   useTranslationContext
 } from "@gnu-taler/web-util/browser";
 import { Fragment, VNode, h } from "preact";
@@ -32,9 +31,9 @@ import { NotificationCard } from 
"../../../../components/menu/index.js";
 import { useSessionContext } from "../../../../context/session.js";
 import { useProductDetails } from "../../../../hooks/product.js";
 import { Notification } from "../../../../utils/types.js";
+import { LoginPage } from "../../../login/index.js";
 import { NotFoundPageOrAdminCreate } from "../../../notfound/index.js";
 import { UpdatePage } from "./UpdatePage.js";
-import { LoginPage } from "../../../login/index.js";
 
 export type Entity = TalerMerchantApi.ProductAddDetail;
 interface Props {
@@ -49,7 +48,7 @@ export default function UpdateProduct({
 }: Props): VNode {
   const result = useProductDetails(pid);
   const [notif, setNotif] = useState<Notification | undefined>(undefined);
-  const { lib } = useMerchantApiContext();
+  const { lib } = useSessionContext();
   const { state } = useSessionContext();
 
   const { i18n } = useTranslationContext();
diff --git 
a/packages/merchant-backoffice-ui/src/paths/instance/templates/create/CreatePage.tsx
 
b/packages/merchant-backoffice-ui/src/paths/instance/templates/create/CreatePage.tsx
index 139ee7aa3..78d7c83ac 100644
--- 
a/packages/merchant-backoffice-ui/src/paths/instance/templates/create/CreatePage.tsx
+++ 
b/packages/merchant-backoffice-ui/src/paths/instance/templates/create/CreatePage.tsx
@@ -28,8 +28,7 @@ import {
   TranslatedString,
 } from "@gnu-taler/taler-util";
 import {
-  useMerchantApiContext,
-  useTranslationContext,
+  useTranslationContext
 } from "@gnu-taler/web-util/browser";
 import { Fragment, VNode, h } from "preact";
 import { useState } from "preact/hooks";
@@ -46,6 +45,7 @@ import { InputSelector } from 
"../../../../components/form/InputSelector.js";
 import { InputToggle } from "../../../../components/form/InputToggle.js";
 import { InputWithAddon } from "../../../../components/form/InputWithAddon.js";
 import { TextField } from "../../../../components/form/TextField.js";
+import { useSessionContext } from "../../../../context/session.js";
 import { useInstanceOtpDevices } from "../../../../hooks/otp.js";
 
 // type Entity = TalerMerchantApi.TemplateAddDetails & { type: Steps };
@@ -69,7 +69,8 @@ interface Props {
 
 export function CreatePage({ onCreate, onBack }: Props): VNode {
   const { i18n } = useTranslationContext();
-  const { url: backendUrl, config } = useMerchantApiContext();
+  const { config } = useSessionContext();
+  const {state:session} = useSessionContext();
   const devices = useInstanceOtpDevices();
 
   const [state, setState] = useState<Partial<Entity>>({
@@ -175,7 +176,7 @@ export function CreatePage({ onCreate, onBack }: Props): 
VNode {
               <InputWithAddon<Entity>
                 name="id"
                 help={
-                  new URL(`templates/${state.id ?? ""}`, backendUrl.href).href
+                  new URL(`templates/${state.id ?? ""}`, 
session.backendUrl.href).href
                 }
                 label={i18n.str`Identifier`}
                 tooltip={i18n.str`Name of the template in URLs.`}
diff --git 
a/packages/merchant-backoffice-ui/src/paths/instance/templates/create/index.tsx 
b/packages/merchant-backoffice-ui/src/paths/instance/templates/create/index.tsx
index f71ca4794..499c7c859 100644
--- 
a/packages/merchant-backoffice-ui/src/paths/instance/templates/create/index.tsx
+++ 
b/packages/merchant-backoffice-ui/src/paths/instance/templates/create/index.tsx
@@ -20,7 +20,7 @@
  */
 
 import { TalerMerchantApi } from "@gnu-taler/taler-util";
-import { useMerchantApiContext, useTranslationContext } from 
"@gnu-taler/web-util/browser";
+import { useTranslationContext } from "@gnu-taler/web-util/browser";
 import { Fragment, VNode, h } from "preact";
 import { useState } from "preact/hooks";
 import { NotificationCard } from "../../../../components/menu/index.js";
@@ -35,7 +35,7 @@ interface Props {
 }
 
 export default function CreateTransfer({ onConfirm, onBack }: Props): VNode {
-  const { lib } = useMerchantApiContext();
+  const { lib } = useSessionContext();
   const { state } = useSessionContext();
   const [notif, setNotif] = useState<Notification | undefined>(undefined);
   const { i18n } = useTranslationContext();
diff --git 
a/packages/merchant-backoffice-ui/src/paths/instance/templates/list/index.tsx 
b/packages/merchant-backoffice-ui/src/paths/instance/templates/list/index.tsx
index f9ab6678b..9e59609c7 100644
--- 
a/packages/merchant-backoffice-ui/src/paths/instance/templates/list/index.tsx
+++ 
b/packages/merchant-backoffice-ui/src/paths/instance/templates/list/index.tsx
@@ -21,7 +21,6 @@
 
 import { HttpStatusCode, TalerError, TalerMerchantApi, assertUnreachable } 
from "@gnu-taler/taler-util";
 import {
-  useMerchantApiContext,
   useTranslationContext
 } from "@gnu-taler/web-util/browser";
 import { VNode, h } from "preact";
@@ -36,9 +35,9 @@ import {
   useInstanceTemplates
 } from "../../../../hooks/templates.js";
 import { Notification } from "../../../../utils/types.js";
+import { LoginPage } from "../../../login/index.js";
 import { NotFoundPageOrAdminCreate } from "../../../notfound/index.js";
 import { ListPage } from "./ListPage.js";
-import { LoginPage } from "../../../login/index.js";
 
 interface Props {
   onCreate: () => void;
@@ -55,7 +54,7 @@ export default function ListTemplates({
 }: Props): VNode {
   const { i18n } = useTranslationContext();
   const [notif, setNotif] = useState<Notification | undefined>(undefined);
-  const { lib } = useMerchantApiContext();
+  const { lib } = useSessionContext();
   const result = useInstanceTemplates();
   const [deleting, setDeleting] =
     useState<TalerMerchantApi.TemplateEntry | null>(null);
diff --git 
a/packages/merchant-backoffice-ui/src/paths/instance/templates/qr/QrPage.tsx 
b/packages/merchant-backoffice-ui/src/paths/instance/templates/qr/QrPage.tsx
index cd6b8b45c..7322ca169 100644
--- a/packages/merchant-backoffice-ui/src/paths/instance/templates/qr/QrPage.tsx
+++ b/packages/merchant-backoffice-ui/src/paths/instance/templates/qr/QrPage.tsx
@@ -19,22 +19,18 @@
  * @author Sebastian Javier Marchano (sebasjm)
  */
 
-import { TalerMerchantApi, stringifyPayTemplateUri } from 
"@gnu-taler/taler-util";
 import {
-  useMerchantApiContext,
-  useTranslationContext,
+  TalerMerchantApi,
+  stringifyPayTemplateUri
+} from "@gnu-taler/taler-util";
+import {
+  useTranslationContext
 } from "@gnu-taler/web-util/browser";
 import { VNode, h } from "preact";
-import { useState } from "preact/hooks";
 import { QR } from "../../../../components/exception/QR.js";
-import {
-  FormErrors,
-  FormProvider,
-} from "../../../../components/form/FormProvider.js";
-import { Input } from "../../../../components/form/Input.js";
-import { InputCurrency } from "../../../../components/form/InputCurrency.js";
+import { useSessionContext } from "../../../../context/session.js";
 
-type Entity = TalerMerchantApi.UsingTemplateDetails;
+// type Entity = TalerMerchantApi.UsingTemplateDetails;
 
 interface Props {
   contract: TalerMerchantApi.TemplateContractDetails;
@@ -42,9 +38,9 @@ interface Props {
   onBack?: () => void;
 }
 
-export function QrPage({ contract, id: templateId, onBack }: Props): VNode {
+export function QrPage({ id: templateId, onBack }: Props): VNode {
   const { i18n } = useTranslationContext();
-  const { config, url: backendUrl } = useMerchantApiContext();
+  const { state } = useSessionContext();
 
   // const [state, setState] = useState<Partial<Entity>>({
   //   amount: contract.amount,
@@ -69,7 +65,7 @@ export function QrPage({ contract, id: templateId, onBack }: 
Props): VNode {
   //   templateParams.summary = state.summary ?? "";
   // }
 
-  const merchantBaseUrl = backendUrl.href;
+  const merchantBaseUrl = state.backendUrl.href;
 
   const payTemplateUri = stringifyPayTemplateUri({
     merchantBaseUrl,
diff --git 
a/packages/merchant-backoffice-ui/src/paths/instance/templates/update/UpdatePage.tsx
 
b/packages/merchant-backoffice-ui/src/paths/instance/templates/update/UpdatePage.tsx
index a4813c8e9..eedb77f28 100644
--- 
a/packages/merchant-backoffice-ui/src/paths/instance/templates/update/UpdatePage.tsx
+++ 
b/packages/merchant-backoffice-ui/src/paths/instance/templates/update/UpdatePage.tsx
@@ -28,8 +28,7 @@ import {
   TranslatedString,
 } from "@gnu-taler/taler-util";
 import {
-  useMerchantApiContext,
-  useTranslationContext,
+  useTranslationContext
 } from "@gnu-taler/web-util/browser";
 import { Fragment, VNode, h } from "preact";
 import { useState } from "preact/hooks";
@@ -45,6 +44,7 @@ import { InputNumber } from 
"../../../../components/form/InputNumber.js";
 import { InputSelector } from "../../../../components/form/InputSelector.js";
 import { InputToggle } from "../../../../components/form/InputToggle.js";
 import { TextField } from "../../../../components/form/TextField.js";
+import { useSessionContext } from "../../../../context/session.js";
 import { useInstanceOtpDevices } from "../../../../hooks/otp.js";
 
 type Entity = {
@@ -67,7 +67,8 @@ interface Props {
 
 export function UpdatePage({ template, onUpdate, onBack }: Props): VNode {
   const { i18n } = useTranslationContext();
-  const { url: backendUrl, config } = useMerchantApiContext();
+  const { config } = useSessionContext();
+  const {state:session} = useSessionContext();
 
   const [state, setState] = useState<Partial<Entity>>({
     description: template.template_description,
@@ -176,7 +177,7 @@ export function UpdatePage({ template, onUpdate, onBack }: 
Props): VNode {
               <div class="level-left">
                 <div class="level-item">
                   <span class="is-size-4">
-                    {new URL(`templates/${template.id}`, backendUrl.href).href}
+                    {new URL(`templates/${template.id}`, 
session.backendUrl.href).href}
                   </span>
                 </div>
               </div>
diff --git 
a/packages/merchant-backoffice-ui/src/paths/instance/templates/update/index.tsx 
b/packages/merchant-backoffice-ui/src/paths/instance/templates/update/index.tsx
index 9e5099947..6185bd2a9 100644
--- 
a/packages/merchant-backoffice-ui/src/paths/instance/templates/update/index.tsx
+++ 
b/packages/merchant-backoffice-ui/src/paths/instance/templates/update/index.tsx
@@ -21,7 +21,6 @@
 
 import { HttpStatusCode, TalerError, TalerMerchantApi, assertUnreachable } 
from "@gnu-taler/taler-util";
 import {
-  useMerchantApiContext,
   useTranslationContext
 } from "@gnu-taler/web-util/browser";
 import { Fragment, VNode, h } from "preact";
@@ -34,9 +33,9 @@ import {
   useTemplateDetails,
 } from "../../../../hooks/templates.js";
 import { Notification } from "../../../../utils/types.js";
+import { LoginPage } from "../../../login/index.js";
 import { NotFoundPageOrAdminCreate } from "../../../notfound/index.js";
 import { UpdatePage } from "./UpdatePage.js";
-import { LoginPage } from "../../../login/index.js";
 
 export type Entity = TalerMerchantApi.TemplatePatchDetails & WithId;
 
@@ -50,7 +49,7 @@ export default function UpdateTemplate({
   onConfirm,
   onBack,
 }: Props): VNode {
-  const { lib } = useMerchantApiContext();
+  const { lib } = useSessionContext();
   const { state } = useSessionContext();
   const result = useTemplateDetails(tid);
   const [notif, setNotif] = useState<Notification | undefined>(undefined);
diff --git 
a/packages/merchant-backoffice-ui/src/paths/instance/templates/use/index.tsx 
b/packages/merchant-backoffice-ui/src/paths/instance/templates/use/index.tsx
index 46d4da8d7..00cb2b827 100644
--- a/packages/merchant-backoffice-ui/src/paths/instance/templates/use/index.tsx
+++ b/packages/merchant-backoffice-ui/src/paths/instance/templates/use/index.tsx
@@ -21,7 +21,6 @@
 
 import { HttpStatusCode, TalerError, TalerMerchantApi, assertUnreachable } 
from "@gnu-taler/taler-util";
 import {
-  useMerchantApiContext,
   useTranslationContext
 } from "@gnu-taler/web-util/browser";
 import { Fragment, VNode, h } from "preact";
@@ -33,9 +32,10 @@ import {
   useTemplateDetails
 } from "../../../../hooks/templates.js";
 import { Notification } from "../../../../utils/types.js";
+import { LoginPage } from "../../../login/index.js";
 import { NotFoundPageOrAdminCreate } from "../../../notfound/index.js";
 import { UsePage } from "./UsePage.js";
-import { LoginPage } from "../../../login/index.js";
+import { useSessionContext } from "../../../../context/session.js";
 
 export type Entity = TalerMerchantApi.TransferInformation;
 interface Props {
@@ -49,7 +49,7 @@ export default function TemplateUsePage({
   onOrderCreated,
   onBack,
 }: Props): VNode {
-  const { lib } = useMerchantApiContext();
+  const { lib } = useSessionContext();
   const result = useTemplateDetails(tid);
   const [notif, setNotif] = useState<Notification | undefined>(undefined);
   const { i18n } = useTranslationContext();
diff --git 
a/packages/merchant-backoffice-ui/src/paths/instance/token/DetailPage.tsx 
b/packages/merchant-backoffice-ui/src/paths/instance/token/DetailPage.tsx
index 0274d6caa..f75ee89b8 100644
--- a/packages/merchant-backoffice-ui/src/paths/instance/token/DetailPage.tsx
+++ b/packages/merchant-backoffice-ui/src/paths/instance/token/DetailPage.tsx
@@ -27,7 +27,7 @@ import { FormProvider } from 
"../../../components/form/FormProvider.js";
 import { Input } from "../../../components/form/Input.js";
 import { NotificationCard } from "../../../components/menu/index.js";
 import { useSessionContext } from "../../../context/session.js";
-import { AccessToken } from "@gnu-taler/taler-util";
+import { AccessToken, createAccessToken } from "@gnu-taler/taler-util";
 
 interface Props {
   hasToken: boolean | undefined;
@@ -67,7 +67,7 @@ export function DetailPage({
   };
 
   const hasErrors = Object.keys(errors).some(
-    (k) => (errors as any)[k] !== undefined,
+    (k) => (errors as Record<string, unknown>)[k] !== undefined,
   );
 
   const { state } = useSessionContext();
@@ -76,11 +76,12 @@ export function DetailPage({
 
   async function submitForm() {
     if (hasErrors) return;
-    const oldToken = hasToken
-      ? (form.old_token as AccessToken)
-      : undefined;
-    const newToken = form.new_token as AccessToken;
-    onNewToken(oldToken, `secret-token:${newToken}` as AccessToken);
+    const oldToken =
+      form.old_token !== undefined && hasToken
+        ? createAccessToken(form.old_token)
+        : undefined;
+    const newToken = createAccessToken(form.new_token!);
+    onNewToken(oldToken, newToken);
   }
 
   return (
@@ -133,8 +134,7 @@ export function DetailPage({
                         class="button"
                         onClick={() => {
                           if (hasToken) {
-                            const oldToken = form.old_token as AccessToken;
-                            onClearToken(oldToken);
+                            onClearToken(form.old_token ? 
createAccessToken(form.old_token) : undefined);
                           } else {
                             onClearToken(undefined);
                           }
diff --git a/packages/merchant-backoffice-ui/src/paths/instance/token/index.tsx 
b/packages/merchant-backoffice-ui/src/paths/instance/token/index.tsx
index cc8f7f9e8..c23e5be17 100644
--- a/packages/merchant-backoffice-ui/src/paths/instance/token/index.tsx
+++ b/packages/merchant-backoffice-ui/src/paths/instance/token/index.tsx
@@ -13,8 +13,14 @@
  You should have received a copy of the GNU General Public License along with
  GNU Taler; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
  */
-import { HttpStatusCode, TalerError, assertUnreachable } from 
"@gnu-taler/taler-util";
-import { useMerchantApiContext, useTranslationContext } from 
"@gnu-taler/web-util/browser";
+import {
+  HttpStatusCode,
+  TalerError,
+  assertUnreachable,
+} from "@gnu-taler/taler-util";
+import {
+  useTranslationContext
+} from "@gnu-taler/web-util/browser";
 import { Fragment, VNode, h } from "preact";
 import { useState } from "preact/hooks";
 import { ErrorLoadingMerchant } from 
"../../../components/ErrorLoadingMerchant.js";
@@ -24,43 +30,40 @@ import { useSessionContext } from 
"../../../context/session.js";
 import { useInstanceDetails } from "../../../hooks/instance.js";
 import { Notification } from "../../../utils/types.js";
 import { LoginPage } from "../../login/index.js";
-import { DetailPage } from "./DetailPage.js";
 import { NotFoundPageOrAdminCreate } from "../../notfound/index.js";
+import { DetailPage } from "./DetailPage.js";
 
 interface Props {
   onChange: () => void;
   onCancel: () => void;
 }
 
-export default function Token({
-  onChange,
-  onCancel,
-}: Props): VNode {
+export default function Token({ onChange, onCancel }: Props): VNode {
   const { i18n } = useTranslationContext();
-  const { lib } = useMerchantApiContext();
+  const { lib } = useSessionContext();
   const { logIn } = useSessionContext();
   const [notif, setNotif] = useState<Notification | undefined>(undefined);
-  const result = useInstanceDetails()
+  const result = useInstanceDetails();
 
-  if (!result) return <Loading />
+  if (!result) return <Loading />;
   if (result instanceof TalerError) {
-    return <ErrorLoadingMerchant error={result} />
+    return <ErrorLoadingMerchant error={result} />;
   }
   if (result.type === "fail") {
-    switch(result.case) {
+    switch (result.case) {
       case HttpStatusCode.Unauthorized: {
-        return <LoginPage />
+        return <LoginPage />;
       }
       case HttpStatusCode.NotFound: {
         return <NotFoundPageOrAdminCreate />;
       }
       default: {
-        assertUnreachable(result)
+        assertUnreachable(result);
       }
     }
   }
 
-  const hasToken = result.body.auth.method === "token"
+  const hasToken = result.body.auth.method === "token";
 
   return (
     <Fragment>
@@ -70,13 +73,24 @@ export default function Token({
         hasToken={hasToken}
         onClearToken={async (currentToken): Promise<void> => {
           try {
-            await 
lib.instance.updateCurrentInstanceAuthentication(currentToken, {
-              method: "external",
-            })
-            onChange();
+            const resp = await 
lib.instance.updateCurrentInstanceAuthentication(
+              currentToken,
+              {
+                method: "external",
+              },
+            );
+            if (resp.type === "ok") {
+              onChange();
+            } else {
+              return setNotif({
+                message: i18n.str`Failed to clear token`,
+                type: "ERROR",
+                description: resp.detail.hint,
+              });
+            }
           } catch (error) {
             if (error instanceof Error) {
-              setNotif({
+              return setNotif({
                 message: i18n.str`Failed to clear token`,
                 type: "ERROR",
                 description: error.message,
@@ -86,29 +100,45 @@ export default function Token({
         }}
         onNewToken={async (currentToken, newToken): Promise<void> => {
           try {
-            await 
lib.instance.updateCurrentInstanceAuthentication(currentToken, {
-              token: newToken,
-              method: "token"
-            })
-            const resp = await 
lib.authenticate.createAccessTokenBearer(newToken, {
-              scope: "write",
-              duration: {
-                d_us: "forever"
+            {
+              const resp =
+                await lib.instance.updateCurrentInstanceAuthentication(
+                  currentToken,
+                  {
+                    token: newToken,
+                    method: "token",
+                  },
+                );
+              if (resp.type === "fail") {
+                return setNotif({
+                  message: i18n.str`Failed to set new token`,
+                  type: "ERROR",
+                  description: resp.detail.hint,
+                });
+              }
+            }
+            const resp = await lib.authenticate.createAccessTokenBearer(
+              newToken,
+              {
+                scope: "write",
+                duration: {
+                  d_us: "forever",
+                },
+                refreshable: true,
               },
-              refreshable: true,
-            })
+            );
             if (resp.type === "ok") {
-              logIn({ token: resp.body.token })
-              onChange();
+              logIn(resp.body.token);
+              return onChange();
             } else {
-              setNotif({
+              return setNotif({
                 message: i18n.str`Failed to set new token`,
                 type: "ERROR",
               });
             }
           } catch (error) {
             if (error instanceof Error) {
-              setNotif({
+              return setNotif({
                 message: i18n.str`Failed to set new token`,
                 type: "ERROR",
                 description: error.message,
diff --git 
a/packages/merchant-backoffice-ui/src/paths/instance/transfers/create/index.tsx 
b/packages/merchant-backoffice-ui/src/paths/instance/transfers/create/index.tsx
index 27eab97ed..428476337 100644
--- 
a/packages/merchant-backoffice-ui/src/paths/instance/transfers/create/index.tsx
+++ 
b/packages/merchant-backoffice-ui/src/paths/instance/transfers/create/index.tsx
@@ -21,16 +21,15 @@
 
 import { TalerError, TalerMerchantApi } from "@gnu-taler/taler-util";
 import {
-  useMerchantApiContext,
-  useTranslationContext,
+  useTranslationContext
 } from "@gnu-taler/web-util/browser";
-import { Fragment, h, VNode } from "preact";
+import { Fragment, VNode, h } from "preact";
 import { useState } from "preact/hooks";
 import { NotificationCard } from "../../../../components/menu/index.js";
+import { useSessionContext } from "../../../../context/session.js";
 import { useInstanceBankAccounts } from "../../../../hooks/bank.js";
 import { Notification } from "../../../../utils/types.js";
 import { CreatePage } from "./CreatePage.js";
-import { useSessionContext } from "../../../../context/session.js";
 
 export type Entity = TalerMerchantApi.TransferInformation;
 interface Props {
@@ -39,7 +38,7 @@ interface Props {
 }
 
 export default function CreateTransfer({ onConfirm, onBack }: Props): VNode {
-  const { lib } = useMerchantApiContext();
+  const { lib } = useSessionContext();
   const { state } = useSessionContext();
   const [notif, setNotif] = useState<Notification | undefined>(undefined);
   const { i18n } = useTranslationContext();
diff --git 
a/packages/merchant-backoffice-ui/src/paths/instance/update/index.tsx 
b/packages/merchant-backoffice-ui/src/paths/instance/update/index.tsx
index 4afc400f8..9da7f7efb 100644
--- a/packages/merchant-backoffice-ui/src/paths/instance/update/index.tsx
+++ b/packages/merchant-backoffice-ui/src/paths/instance/update/index.tsx
@@ -15,7 +15,6 @@
  */
 import { HttpStatusCode, TalerError, TalerMerchantApi, 
TalerMerchantInstanceHttpClient, TalerMerchantManagementResultByMethod, 
assertUnreachable } from "@gnu-taler/taler-util";
 import {
-  useMerchantApiContext,
   useTranslationContext
 } from "@gnu-taler/web-util/browser";
 import { Fragment, VNode, h } from "preact";
@@ -30,8 +29,8 @@ import {
 } from "../../../hooks/instance.js";
 import { Notification } from "../../../utils/types.js";
 import { LoginPage } from "../../login/index.js";
-import { UpdatePage } from "./UpdatePage.js";
 import { NotFoundPageOrAdminCreate } from "../../notfound/index.js";
+import { UpdatePage } from "./UpdatePage.js";
 
 export interface Props {
   onBack: () => void;
@@ -44,14 +43,14 @@ export interface Props {
 }
 
 export default function Update(props: Props): VNode {
-  const { lib } = useMerchantApiContext();
+  const { lib } = useSessionContext();
   const updateInstance = lib.instance.updateCurrentInstance.bind(lib.instance)
   const result = useInstanceDetails();
   return CommonUpdate(props, result, updateInstance,);
 }
 
 export function AdminUpdate(props: Props & { instanceId: string }): VNode {
-  const { lib } = useMerchantApiContext();
+  const { lib } = useSessionContext();
   const t = lib.subInstanceApi(props.instanceId).instance;
   const updateInstance = t.updateCurrentInstance.bind(t)
   const result = useManagedInstanceDetails(props.instanceId);
diff --git 
a/packages/merchant-backoffice-ui/src/paths/instance/webhooks/create/index.tsx 
b/packages/merchant-backoffice-ui/src/paths/instance/webhooks/create/index.tsx
index e4d260b04..70f246ff1 100644
--- 
a/packages/merchant-backoffice-ui/src/paths/instance/webhooks/create/index.tsx
+++ 
b/packages/merchant-backoffice-ui/src/paths/instance/webhooks/create/index.tsx
@@ -19,14 +19,14 @@
  * @author Sebastian Javier Marchano (sebasjm)
  */
 
-import { useMerchantApiContext, useTranslationContext } from 
"@gnu-taler/web-util/browser";
-import { Fragment, h, VNode } from "preact";
+import { TalerMerchantApi } from "@gnu-taler/taler-util";
+import { useTranslationContext } from "@gnu-taler/web-util/browser";
+import { Fragment, VNode, h } from "preact";
 import { useState } from "preact/hooks";
 import { NotificationCard } from "../../../../components/menu/index.js";
+import { useSessionContext } from "../../../../context/session.js";
 import { Notification } from "../../../../utils/types.js";
 import { CreatePage } from "./CreatePage.js";
-import { TalerMerchantApi } from "@gnu-taler/taler-util";
-import { useSessionContext } from "../../../../context/session.js";
 
 export type Entity = TalerMerchantApi.WebhookAddDetails;
 interface Props {
@@ -37,7 +37,7 @@ interface Props {
 export default function CreateWebhook({ onConfirm, onBack }: Props): VNode {
   const [notif, setNotif] = useState<Notification | undefined>(undefined);
   const { i18n } = useTranslationContext();
-  const { lib } = useMerchantApiContext();
+  const { lib } = useSessionContext();
   const { state } = useSessionContext();
 
   return (
diff --git 
a/packages/merchant-backoffice-ui/src/paths/instance/webhooks/list/index.tsx 
b/packages/merchant-backoffice-ui/src/paths/instance/webhooks/list/index.tsx
index 988a54604..789b8d73b 100644
--- a/packages/merchant-backoffice-ui/src/paths/instance/webhooks/list/index.tsx
+++ b/packages/merchant-backoffice-ui/src/paths/instance/webhooks/list/index.tsx
@@ -26,8 +26,7 @@ import {
   assertUnreachable,
 } from "@gnu-taler/taler-util";
 import {
-  useMerchantApiContext,
-  useTranslationContext,
+  useTranslationContext
 } from "@gnu-taler/web-util/browser";
 import { Fragment, VNode, h } from "preact";
 import { useState } from "preact/hooks";
@@ -37,9 +36,9 @@ import { NotificationCard } from 
"../../../../components/menu/index.js";
 import { useSessionContext } from "../../../../context/session.js";
 import { useInstanceWebhooks } from "../../../../hooks/webhooks.js";
 import { Notification } from "../../../../utils/types.js";
+import { LoginPage } from "../../../login/index.js";
 import { NotFoundPageOrAdminCreate } from "../../../notfound/index.js";
 import { ListPage } from "./ListPage.js";
-import { LoginPage } from "../../../login/index.js";
 
 interface Props {
   onCreate: () => void;
@@ -49,7 +48,7 @@ interface Props {
 export default function ListWebhooks({ onCreate, onSelect }: Props): VNode {
   const { i18n } = useTranslationContext();
   const [notif, setNotif] = useState<Notification | undefined>(undefined);
-  const { lib } = useMerchantApiContext();
+  const { lib } = useSessionContext();
   const { state } = useSessionContext();
   const result = useInstanceWebhooks();
 
diff --git 
a/packages/merchant-backoffice-ui/src/paths/instance/webhooks/update/index.tsx 
b/packages/merchant-backoffice-ui/src/paths/instance/webhooks/update/index.tsx
index 1253cd9a2..5b2ba7bb9 100644
--- 
a/packages/merchant-backoffice-ui/src/paths/instance/webhooks/update/index.tsx
+++ 
b/packages/merchant-backoffice-ui/src/paths/instance/webhooks/update/index.tsx
@@ -21,7 +21,6 @@
 
 import { HttpStatusCode, TalerError, TalerMerchantApi, assertUnreachable } 
from "@gnu-taler/taler-util";
 import {
-  useMerchantApiContext,
   useTranslationContext
 } from "@gnu-taler/web-util/browser";
 import { Fragment, VNode, h } from "preact";
@@ -34,9 +33,9 @@ import {
   useWebhookDetails,
 } from "../../../../hooks/webhooks.js";
 import { Notification } from "../../../../utils/types.js";
+import { LoginPage } from "../../../login/index.js";
 import { NotFoundPageOrAdminCreate } from "../../../notfound/index.js";
 import { UpdatePage } from "./UpdatePage.js";
-import { LoginPage } from "../../../login/index.js";
 
 export type Entity = TalerMerchantApi.WebhookPatchDetails & WithId;
 
@@ -50,7 +49,7 @@ export default function UpdateWebhook({
   onConfirm,
   onBack,
 }: Props): VNode {
-  const { lib } = useMerchantApiContext();
+  const { lib } = useSessionContext();
   const { state } = useSessionContext();
   const result = useWebhookDetails(tid);
   const [notif, setNotif] = useState<Notification | undefined>(undefined);
diff --git a/packages/merchant-backoffice-ui/src/paths/login/index.tsx 
b/packages/merchant-backoffice-ui/src/paths/login/index.tsx
index 30b5c37bd..272c40b55 100644
--- a/packages/merchant-backoffice-ui/src/paths/login/index.tsx
+++ b/packages/merchant-backoffice-ui/src/paths/login/index.tsx
@@ -19,10 +19,9 @@
  * @author Sebastian Javier Marchano (sebasjm)
  */
 
-import { HttpStatusCode } from "@gnu-taler/taler-util";
+import { HttpStatusCode, createAccessToken } from "@gnu-taler/taler-util";
 import {
-  useMerchantApiContext,
-  useTranslationContext,
+  useTranslationContext
 } from "@gnu-taler/web-util/browser";
 import { ComponentChildren, Fragment, VNode, h } from "preact";
 import { useState } from "preact/hooks";
@@ -43,58 +42,19 @@ const tokenRequest = {
 export function LoginPage(_p: Props): VNode {
   const [token, setToken] = useState("");
   const [notif, setNotif] = useState<Notification | undefined>(undefined);
-  const { state, logIn, impersonate } = useSessionContext();
-  const { lib } = useMerchantApiContext();
+  const { state, logIn } = useSessionContext();
+  const { lib } = useSessionContext();
 
   const { i18n } = useTranslationContext();
 
-  async function doImpersonateImpl(instanceId: string) {
-    const newInstanceApi = lib.subInstanceApi(instanceId);
-    const cfg = await newInstanceApi.instance.getConfig();
-    if (cfg.type !== "ok") {
-      setNotif({
-        message: "Could not load the configuration of this instance.",
-        description: newInstanceApi.instance.baseUrl,
-        type: "ERROR",
-      });
-      return;
-    }
-    const result = await newInstanceApi.authenticate.createAccessTokenBearer(
-      token,
-      tokenRequest,
-    );
-    
-    if (result.type === "ok") {
-      const { token } = result.body;
-      impersonate({ instance: instanceId, baseUrl: new 
URL(newInstanceApi.instance.baseUrl), token });
-      return;
-    } else {
-      switch (result.case) {
-        case HttpStatusCode.Unauthorized: {
-          setNotif({
-            message: "Your password is incorrect",
-            type: "ERROR",
-          });
-          return;
-        }
-        case HttpStatusCode.NotFound: {
-          setNotif({
-            message: "Your instance not found",
-            type: "ERROR",
-          });
-          return;
-        }
-      }
-    }
-  }
   async function doLoginImpl() {
     const result = await lib.authenticate.createAccessTokenBearer(
-      token,
+      createAccessToken(token),
       tokenRequest,
     );
     if (result.type === "ok") {
       const { token } = result.body;
-      logIn({ token });
+      logIn(token);
       return;
     } else {
       switch (result.case) {
@@ -116,73 +76,6 @@ export function LoginPage(_p: Props): VNode {
     }
   }
 
-  if (state.status === "loggedIn" && state.impersonate !== undefined) {
-    //the user is loggedin but trying to do an impersonation
-    return (
-      <div class="columns is-centered" style={{ margin: "auto" }}>
-        <div class="column is-two-thirds ">
-          <div class="modal-card" style={{ width: "100%", margin: 0 }}>
-            <header
-              class="modal-card-head"
-              style={{ border: "1px solid", borderBottom: 0 }}
-            >
-              <p class="modal-card-title">{i18n.str`Login required`}</p>
-            </header>
-            <section
-              class="modal-card-body"
-              style={{ border: "1px solid", borderTop: 0, borderBottom: 0 }}
-            >
-              <p>
-                <i18n.Translate>
-                  Need the access token for the instance{" "}
-                  <b>"{state.instance}"</b>
-                </i18n.Translate>
-              </p>
-              <div class="field is-horizontal">
-                <div class="field-label is-normal">
-                  <label class="label">
-                    <i18n.Translate>Access Token</i18n.Translate>
-                  </label>
-                </div>
-                <div class="field-body">
-                  <div class="field">
-                    <p class="control is-expanded">
-                      <input
-                        class="input"
-                        type="password"
-                        placeholder={"current access token"}
-                        name="token"
-                        onKeyPress={(e) =>
-                          e.keyCode === 13
-                            ? doImpersonateImpl(state.instance)
-                            : null
-                        }
-                        value={token}
-                        onInput={(e): void => setToken(e?.currentTarget.value)}
-                      />
-                    </p>
-                  </div>
-                </div>
-              </div>
-            </section>
-            <footer
-              class="modal-card-foot "
-              style={{
-                justifyContent: "flex-end",
-                border: "1px solid",
-                borderTop: 0,
-              }}
-            >
-              <AsyncButton onClick={() => doImpersonateImpl(state.instance)}>
-                <i18n.Translate>Confirm</i18n.Translate>
-              </AsyncButton>
-            </footer>
-          </div>
-        </div>
-      </div>
-    );
-  }
-
   return (
     <Fragment>
       <NotificationCard notification={notif} />
diff --git a/packages/taler-harness/src/index.ts 
b/packages/taler-harness/src/index.ts
index 2dcde39b9..0f282e123 100644
--- a/packages/taler-harness/src/index.ts
+++ b/packages/taler-harness/src/index.ts
@@ -34,6 +34,7 @@ import {
   TalerMerchantInstanceHttpClient,
   TalerMerchantManagementHttpClient,
   TransactionsResponse,
+  createAccessToken,
   decodeCrock,
   encodeCrock,
   generateIban,
@@ -55,7 +56,8 @@ import {
   WalletApiOperation,
 } from "@gnu-taler/taler-wallet-core";
 import {
-  downloadExchangeInfo, topupReserveWithBank,
+  downloadExchangeInfo,
+  topupReserveWithBank,
 } from "@gnu-taler/taler-wallet-core/dbless";
 import { deepStrictEqual } from "assert";
 import fs from "fs";
@@ -614,7 +616,10 @@ deploymentCli
     },
   )
   .maybeOption("bankToken", ["--bank-admin-token"], clk.STRING, {
-    help: "libeufin bank admin's password if the account creation is 
restricted",
+    help: "libeufin bank admin's token if the account creation is restricted",
+  })
+  .maybeOption("bankPassword", ["--bank-admin-password"], clk.STRING, {
+    help: "libeufin bank admin's password if the account creation is 
restricted, it will override --bank-admin-token",
   })
   .requiredOption("name", ["--legal-name"], clk.STRING, {
     help: "legal name of the merchant",
@@ -638,10 +643,13 @@ deploymentCli
     help: "if everything worked ok, change the password of the accounts at the 
end",
   })
   .action(async (args) => {
-    const managementToken = args.provisionBankMerchant
-      .merchantToken as AccessToken;
-    const bankAdminPassword = args.provisionBankMerchant
-      .bankToken as AccessToken;
+    const managementToken = createAccessToken(
+      args.provisionBankMerchant.merchantToken,
+    );
+    const bankAdminPassword = args.provisionBankMerchant.bankPassword;
+    const bankAdminTokenArg = args.provisionBankMerchant.bankToken
+      ? createAccessToken(args.provisionBankMerchant.bankToken)
+      : undefined;
     const id = args.provisionBankMerchant.id;
     const name = args.provisionBankMerchant.name;
     const email = args.provisionBankMerchant.email;
@@ -694,21 +702,48 @@ deploymentCli
       return;
     }
 
+    let bankAdminToken: AccessToken | undefined;
+    if (bankAdminPassword) {
+      const adminAuth = new TalerAuthenticationHttpClient(
+        bank.getAuthenticationAPI("admin").href,
+        httpLib,
+      );
+
+      const resp = await adminAuth.createAccessTokenBasic(
+        "admin",
+        bankAdminPassword,
+        {
+          scope: "write",
+          duration: {
+            d_us: 1000 * 1000 * 10, //10 secs
+          },
+          refreshable: false,
+        },
+      );
+      if (resp.type === "fail") {
+        logger.error(`could not get bank admin token from password.`);
+        return;
+      }
+      bankAdminToken = resp.body.access_token;
+    } else {
+      bankAdminToken = bankAdminTokenArg;
+    }
+
     /**
      * create bank account
      */
     let accountPayto: PaytoString;
     {
-      const resp = await bank.createAccount(bankAdminPassword, {
+      const resp = await bank.createAccount(bankAdminToken, {
         name: name,
         password: password,
         username: id,
         contact_data:
           email || phone
             ? {
-              email: email,
-              phone: phone,
-            }
+                email: email,
+                phone: phone,
+              }
             : undefined,
       });
 
@@ -730,7 +765,7 @@ deploymentCli
         address: {},
         auth: {
           method: "token",
-          token: `secret-token:${password}`,
+          token: createAccessToken(password),
         },
         default_pay_delay: Duration.toTalerProtocolDuration(
           Duration.fromSpec({ hours: 1 }),
@@ -762,7 +797,7 @@ deploymentCli
      */
     {
       const resp = await merchantInstance.addBankAccount(
-        password as AccessToken,
+        createAccessToken(password),
         {
           payto_uri: accountPayto,
           credit_facade_url: bank.getRevenueAPI(id).href,
@@ -805,7 +840,7 @@ deploymentCli
 
       {
         const resp = await merchantInstance.addTemplate(
-          password as AccessToken,
+          createAccessToken(password),
           {
             template_id: "default",
             template_description: "First template",
@@ -840,7 +875,7 @@ deploymentCli
 
     let finalPassword = password;
     if (args.provisionBankMerchant.randomPassword) {
-      const prevPassword = password as AccessToken;
+      const prevPassword = password;
       const randomPassword = encodeCrock(randomBytes(16));
       logger.info("random password: ", randomPassword);
       let token: AccessToken;
@@ -885,10 +920,10 @@ deploymentCli
 
       {
         const resp = await 
merchantInstance.updateCurrentInstanceAuthentication(
-          prevPassword,
+          createAccessToken(prevPassword),
           {
             method: "token",
-            token: `secret-token:${randomPassword}` as AccessToken,
+            token: createAccessToken(randomPassword),
           },
         );
         if (resp.type === "fail") {
@@ -902,7 +937,7 @@ deploymentCli
 
       {
         const resp = await merchantInstance.updateBankAccount(
-          randomPassword as AccessToken,
+          createAccessToken(randomPassword),
           wireAccount,
           {
             credit_facade_url: bank.getRevenueAPI(id).href,
@@ -960,17 +995,12 @@ deploymentCli
     const httpLib = createPlatformHttpLib({});
     const baseUrl = args.provisionMerchantInstance.merchantApiBaseUrl;
     const api = new TalerMerchantManagementHttpClient(baseUrl, httpLib);
-    const mt = args.provisionMerchantInstance.managementToken;
-    const mtWithoutPrefix = mt.startsWith("secret-token:")
-      ? mt.substring("secret-token:".length)
-      : mt;
-    const managementToken = mtWithoutPrefix as AccessToken;
-
-    const it = args.provisionMerchantInstance.instanceToken;
-    const itWithoutPrefix = it.startsWith("secret-token:")
-      ? it.substring("secret-token:".length)
-      : it;
-    const instanceToken = itWithoutPrefix as AccessToken;
+    const managementToken = createAccessToken(
+      args.provisionMerchantInstance.managementToken,
+    );
+    const instanceToken = createAccessToken(
+      args.provisionMerchantInstance.instanceToken,
+    );
     const instanceId = args.provisionMerchantInstance.id;
     const instancceName = args.provisionMerchantInstance.name;
     const bankURL = args.provisionMerchantInstance.bankURL;
@@ -982,7 +1012,7 @@ deploymentCli
       address: {},
       auth: {
         method: "token",
-        token: `secret-token:${instanceToken}`,
+        token: instanceToken,
       },
       default_pay_delay: Duration.toTalerProtocolDuration(
         Duration.fromSpec({ hours: 1 }),
@@ -1011,10 +1041,10 @@ deploymentCli
       credit_facade_credentials:
         bankUser && bankPassword
           ? {
-            type: "basic",
-            username: bankUser,
-            password: bankPassword,
-          }
+              type: "basic",
+              username: bankUser,
+              password: bankPassword,
+            }
           : undefined,
     });
     if (createAccountResp.type != "ok") {
diff --git a/packages/taler-util/src/codec.ts b/packages/taler-util/src/codec.ts
index 701fc8835..678c3f092 100644
--- a/packages/taler-util/src/codec.ts
+++ b/packages/taler-util/src/codec.ts
@@ -360,6 +360,40 @@ export function codecForStringURL(shouldEndWithSlash?: 
boolean): Codec<string> {
   };
 }
 
+/**
+ * Return a codec for a value that must be a string.
+ */
+export function codecForURL(shouldEndWithSlash?: boolean): Codec<URL> {
+  return {
+    decode(x: any, c?: Context): URL {
+      if (typeof x !== "string") {
+        throw new DecodingError(
+          `expected string at ${renderContext(c)} but got ${typeof x}`,
+        );
+      }
+      if (shouldEndWithSlash && !x.endsWith("/")) {
+        throw new DecodingError(
+          `expected URL string that ends with slash at ${renderContext(
+            c,
+          )} but got ${x}`,
+        );
+      }
+      try {
+        const url = new URL(x);
+        return url;
+      } catch (e) {
+        if (e instanceof Error) {
+          throw new DecodingError(e.message);
+        } else {
+          throw new DecodingError(
+            `expected an URL string at ${renderContext(c)} but got "${x}"`,
+          );
+        }
+      }
+    },
+  };
+}
+
 /**
  * Codec that allows any value.
  */
diff --git a/packages/taler-util/src/http-client/authentication.ts 
b/packages/taler-util/src/http-client/authentication.ts
index b8affee7b..8897a2fa0 100644
--- a/packages/taler-util/src/http-client/authentication.ts
+++ b/packages/taler-util/src/http-client/authentication.ts
@@ -92,14 +92,14 @@ export class TalerAuthenticationHttpClient {
    * @returns
    */
   async createAccessTokenBearer(
-    token: string,
+    token: AccessToken,
     body: TalerAuthentication.TokenRequest,
   ) {
     const url = new URL(`token`, this.baseUrl);
     const resp = await this.httpLib.fetch(url.href, {
       method: "POST",
       headers: {
-        Authorization: makeBearerTokenAuthHeader(token as AccessToken),
+        Authorization: makeBearerTokenAuthHeader(token),
       },
       body,
     });
diff --git a/packages/taler-util/src/http-client/types.ts 
b/packages/taler-util/src/http-client/types.ts
index 35603264a..94eafb329 100644
--- a/packages/taler-util/src/http-client/types.ts
+++ b/packages/taler-util/src/http-client/types.ts
@@ -185,10 +185,24 @@ export interface LoginToken {
 }
 
 declare const __ac_token: unique symbol;
+/**
+ * Use `createAccessToken(string)` function to build one.
+ */
 export type AccessToken = string & {
   [__ac_token]: true;
 };
 
+/**
+ * Create a rfc8959 access token.
+ * Adds secret-token: prefix if there is none.
+ * 
+ * @param token 
+ * @returns 
+ */
+export function createAccessToken(token: string): AccessToken {
+  return (token.startsWith("secret-token:") ? token : `secret-token:${token}`) 
as AccessToken
+}
+
 declare const __officer_signature: unique symbol;
 export type OfficerSignature = string & {
   [__officer_signature]: true;
@@ -3604,7 +3618,7 @@ export namespace TalerMerchantApi {
     // After the auth token has been set (with method "token"),
     // the value must be provided in a "Authorization: Bearer $token"
     // header.
-    token?: string;
+    token?: AccessToken;
   }
 
   export interface InstanceReconfigurationMessage {
diff --git a/packages/taler-util/src/http-client/utils.ts 
b/packages/taler-util/src/http-client/utils.ts
index c579cd852..bf186ce46 100644
--- a/packages/taler-util/src/http-client/utils.ts
+++ b/packages/taler-util/src/http-client/utils.ts
@@ -39,7 +39,7 @@ export function makeBasicAuthHeader(
  * @returns
  */
 export function makeBearerTokenAuthHeader(token: AccessToken): string {
-  return `Bearer secret-token:${token}`;
+  return `Bearer ${token}`;
 }
 
 /**
diff --git a/packages/web-util/src/context/activity.ts 
b/packages/web-util/src/context/activity.ts
index 9a16f6673..422b25909 100644
--- a/packages/web-util/src/context/activity.ts
+++ b/packages/web-util/src/context/activity.ts
@@ -26,7 +26,7 @@ export class ActiviyTracker<Event> {
     this.notify = this.notify.bind(this)
     this.subscribe = this.subscribe.bind(this)
   }
-  notify(data: Event) {
+  notify(data: Event): void {
     this.observers.forEach((observer) => observer(data))
   }
   subscribe(func: Listener<Event>): Unsuscriber {
diff --git a/packages/web-util/src/context/merchant-api.ts 
b/packages/web-util/src/context/merchant-api.ts
index 9998b3aeb..03c95d48e 100644
--- a/packages/web-util/src/context/merchant-api.ts
+++ b/packages/web-util/src/context/merchant-api.ts
@@ -69,7 +69,9 @@ enum VersionHint {
 }
 
 type Evictors = {
-  management?: CacheEvictor<TalerMerchantManagementCacheEviction | 
TalerMerchantInstanceCacheEviction>;
+  management?: CacheEvictor<
+    TalerMerchantManagementCacheEviction | TalerMerchantInstanceCacheEviction
+  >;
 };
 
 type ConfigResult<T> =
@@ -81,7 +83,7 @@ export type ConfigResultFail<T> =
   | { type: "incompatible"; result: T; supported: string }
   | { type: "error"; error: TalerError };
 
-const CONFIG_FAIL_TRY_AGAIN_MS = 5000
+const CONFIG_FAIL_TRY_AGAIN_MS = 5000;
 
 export const MerchantApiProvider = ({
   baseUrl,
@@ -108,7 +110,7 @@ export const MerchantApiProvider = ({
     let keepRetrying = true;
     async function testConfig(): Promise<void> {
       try {
-        const config = await getRemoteConfig();  
+        const config = await getRemoteConfig();
         if (LibtoolVersion.compare(VERSION, config.version)) {
           setChecked({ type: "ok", config, hints: [] });
         } else {
@@ -122,7 +124,7 @@ export const MerchantApiProvider = ({
         if (error instanceof TalerError) {
           if (keepRetrying) {
             setTimeout(() => {
-              testConfig()
+              testConfig();
             }, CONFIG_FAIL_TRY_AGAIN_MS);
           }
           setChecked({ type: "error", error });
@@ -135,7 +137,7 @@ export const MerchantApiProvider = ({
     return () => {
       // on unload, stop retry
       keepRetrying = false;
-    }
+    };
   }, []);
 
   if (!checked || checked.type !== "ok") {
@@ -183,30 +185,18 @@ function buildMerchantApiClient(
     httpLib,
   );
 
-  // const instance = (instanceId: string): TalerMerchantInstanceHttpClient => 
{
-  //   return new TalerMerchantInstanceHttpClient(
-  //     management.getSubInstanceAPI(instanceId).href,
-  //     httpLib,
-  //     evictors.instance ? evictors.instance(instanceId) : undefined,
-  //   );
-  // }
-  // const impersonate = (instanceId: string): TalerAuthenticationHttpClient 
=> {
-  //   return new TalerAuthenticationHttpClient(
-  //     instance(instanceId).getAuthenticationAPI().href,
-  //     httpLib,
-  //   );
-  // }
-  const rootUrl = url;
   function getSubInstanceAPI(instanceId: string): MerchantLib {
-    const newURL = new URL(`instance/${instanceId}/`, rootUrl);
-    const api = buildMerchantApiClient(newURL, evictors);
+    const api = buildMerchantApiClient(
+      instance.getSubInstanceAPI(instanceId) as URL,
+      evictors,
+    );
     return api.lib;
   }
 
   async function getRemoteConfig(): Promise<TalerMerchantApi.VersionResponse> {
     const resp = await instance.getConfig();
     if (resp.type === "fail") {
-      throw TalerError.fromUncheckedDetail(resp.detail)
+      throw TalerError.fromUncheckedDetail(resp.detail);
     }
     return resp.body;
   }

-- 
To stop receiving notification emails like this one, please contact
gnunet@gnunet.org.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]