question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Changing the Configuration at Runtime

See original GitHub issue

I would like to change the configuration at runtime:

const [someConvention, setSomeConvention] = useState();
const configuration = getConfiguration(someConvention);

return <AuthenticationProvider
            configuration={configuration}
            {...restOfProps}
        >
        {children}
        </AuthenticationProvider>

But because of how authenticationServiceInternal in authenticationService.ts is made with that if at the beginning, new configurations will never be set.

export const authenticationServiceInternal = (
  WebStorageStateStoreInt: typeof WebStorageStateStore
) => (configuration: UserManagerSettings, UserStore?: UserStoreType) => {
  if (userManager) {
    return userManager;
  }
[...]

Can you please instruct me on what is the proper way to change the configuration at runtime without having to access setUserManager and set it to null. The code doesn’t seem to want that export being used by client developers … I think. And it feels like a dirty workaround. Maybe include a comparison in that if to see if the config is changed?

Issue Analytics

  • State:open
  • Created 3 years ago
  • Reactions:2
  • Comments:36 (16 by maintainers)

github_iconTop GitHub Comments

2reactions
dragos-roscacommented, May 5, 2022

Hello, I have a hard time sharing code in a sand box because there are 3 projects that need to go up (React + Apollo frontend, Nodejs GQL backend and the Identity server dotnet core).

So here is an attempt at putting here the important part. If it’s not enough I will try to make a sand box because we don’t need to involve GQL right now. I can show you that the token in oidcDatabase is not the same as the token in the session storage.

Here we have the configuration function. The important part is the acr_values that value dictates a property inside the access token. Based on the acr_values the Identity server sets tid (tenant id) inside the token

const root = `${window.location.protocol}//${window.location.hostname}${window.location.port ? `:${window.location.port}` : ''}`
const AUTH = {
  CALLBACK: '/authentication/callback',
  SILENT_CALLBACK: '/authentication/silent_callback'
}

const getAuthenticationConfiguration = tenant => {
  const acr_values = isNullOrWhitespace(tenant) ? undefined : `tenant:${tenant}`
  return {
    client_id: env.REACT_APP_IDENTITY_CLIENT_ID,
    authority: env.REACT_APP_IDENTITY_AUTHORITY,
    redirect_uri: `${root}${AUTH.CALLBACK}`,
    silent_redirect_uri: `${root}${AUTH.SILENT_CALLBACK}`,
    scope: 'openid profile ' + env.REACT_APP_IDENTITY_SCOPE,
    register_uri: `${env.REACT_APP_IDENTITY_AUTHORITY}/${env.REACT_APP_REGISTER_REDIRECT_URL}?returnUrl=${root}/register&clientId=${env.REACT_APP_IDENTITY_CLIENT_ID}`,
    extras: {
      response_type: 'code',
      post_logout_redirect_uri: `${root}`,
      loadUserInfo: true,
      automaticSilentRenew: true,
      revokeAccessTokenOnSignout: true,
      triggerAuthFlow: true,
      acr_values
    }
  }
}

export default getAuthenticationConfiguration

Here is my authentication wrapper. I create a state that is connected to the session storage. From here we expose a method available for the whole project that can change the tenant value. When this value is change, we get a new acr_values in our configuration that will dictate the value of the tid in our token.

import { Oidc } from '@axa-fr/react-oidc-context/dist/vanilla'

export const useSessionStorage = key => {
  const [state, setState] = useState(window.sessionStorage.getItem(key))
  useEffect(() => {
    state ? window.sessionStorage.setItem(key, state) : window.sessionStorage.removeItem(key)
  }, [key, state])

  return [state, setState]
}

export const TenantContext = createContext()
const TenantAuthenticationProvider = props => {
  const { children } = props
  const [tenant, setTenant] = useSessionStorage('tid')

// First Problem:
// I have to force this "refreshTokensAsync()" to get a synchronization between this tenant and the value in the token.
// If this is missing, the synchronization will happen at the next token refresh (when it will expire)
// But this synchronization will happen only in the session storage
  useEffect(() => {
    if (!tenant) return

    const oidc = Oidc.get()
    if (!oidc?.userInfo) return

    if (oidc.userInfo.tid !== tenant) oidc.refreshTokensAsync()
    console.log(oidc)
  }, [tenant])

  const setTenantCallback = useCallback(
    async e => {
      if ((!e && !tenant) || `${e}`.toUpperCase() === `${tenant}`.toUpperCase()) {
        return
      }

      setTenant(e)
    },
    [setTenant, tenant]
  )

  const configuration = getAuthenticationConfiguration(tenant)

  return (
    <TenantContext.Provider value={setTenantCallback}>
      <OidcProvider
        configuration={configuration}
        authenticating={Authenticating}
        callbackSuccessComponent={CallbackPage}
        loadingComponent={NotAuthenticated}
        sessionLostComponent={SessionExpired}
        callbackErrorComponent={Forbidden}
      >
        {children}
      </OidcProvider>
    </TenantContext.Provider>
  )
}

TenantAuthenticationProvider.propTypes = { children: PropTypes.element.isRequired }

export default TenantAuthenticationProvider

And now to show the difference on screen

import React, { Fragment, useCallback, useState } from 'react'
import { Hidden, Typography } from '@material-ui/core'
import { useOidcAccessToken } from '@axa-fr/react-oidc-context'
import { Button } from '@bit/totalsoft_oss.react-mui.kit.core'

function parseJwt(token) {
  const base64Url = token.split('.')[1]
  const base64 = base64Url.replace(/-/g, '+').replace(/_/g, '/')
  const jsonPayload = decodeURIComponent(
    atob(base64)
      .split('')
      .map(function (c) {
        return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2)
      })
      .join('')
  )

  return JSON.parse(jsonPayload)
}

function PrivacySettings() {
  const [refresh, setRefresh] = useState(false)
  const handleClick = useCallback(() => {
    setRefresh(r => !r)
  }, [])

  const oidcTokens = useOidcAccessToken()
  const sessionTokens = JSON.parse(sessionStorage.getItem('default'))?.tokens

  return (
    <Fragment>
      <Button onClick={handleClick}>Manually refresh session storage readout</Button>
      <Hidden>{refresh}</Hidden>
      <Typography variant='h5'>This is the token from &quot;useOidcAccessToken()&quot;</Typography>
      {oidcTokens && <Typography color='primary'>{JSON.stringify(parseJwt(oidcTokens.accessToken))}</Typography>}
      <hr />
      <Typography variant='h5'>This is the token from &quot;sessionStorage.getItem(&apos;default&apos;)&quot;</Typography>
      {sessionTokens && <Typography color='error'>{JSON.stringify(parseJwt(sessionTokens.accessToken))}</Typography>}
    </Fragment>
  )
}

export default PrivacySettings

And now for some step by step pictures. When I first login everything is good image

Now lets change the tenant and reread the session storage token image

The labels on the left are the names from the session storage that dictates the acr_values they are not taken from the token.

Hope this helps and if it doesn’t I will try to see if I can make a sand box for you to test.

Thank you for helping me and have a great day!

2reactions
guillaume-chervetcommented, Dec 10, 2020

Yes, i would like to work on it. But i am lacking of time. Thank you for the message

Read more comments on GitHub >

github_iconTop Results From Across the Web

How do I modify config file at runtime - Stack Overflow
I need to change the config file myApp.exe.config at runtime. How to make sure that the program would be started to work with...
Read more >
How to change configuration at runtime ? · Issue #923 - GitHub
Yes, switching configs at runtime is not possible. Not without a reload.
Read more >
Modifying Configuration Settings at Runtime - CodeProject
This article will demonstrate how to add, delete, and update key value pairs in an App.config file.
Read more >
Modifying .NET Configuration Files at Runtime - C# Corner
Now set the value to be changed in the AdminConsole application and click on the "Modify" button. Changing-the-configuration-element.gif. Figure ...
Read more >
Runtime Configuration - ActiveMQ
From version 5.9.0 a new broker plugin will allow selective changes to a broker xml configuration to take effect without broker restart.
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found