Customer Portal: installation and setup
The Customer Portal is a website your company runs on its own server. Your customers sign in with a code sent to them by email, and see their hires, deliveries, certificates and billing.
START-HERE.html, where they are in English, Spanish, French, Italian, German and Portuguese.This page takes you from the download to a portal that runs as a service, answers over HTTPS, is connected to Business Central and has its first customer invited. Work through the sections in order. Sections 2 and 3 are alternatives: follow the one for your server. The portal is a preview, so expect details to change before its first full release.
A dark block is something you type, and the line above it says where. A light block is the contents of a file.
1 Before you start
Get these in place before you install anything. At the end of this section you will have four values, which the portal asks for in section 5.
Business Central
- Essential Rental 28.4.6 or later, in Business Central online.
- The Customer Portal licensed for each company that will use it. It is a licensed part of Essential Rental and is in preview: ask H2 Business Systems to add it to your subscription. In a company that does not have it, opening Customer Portal Setup answers "The Customer Portal is not available under your current subscription."
A server that is always on
- Windows Server 2019 or later (64-bit), or a 64-bit Linux with systemd, for example Debian 12, Ubuntu 22.04 or later, or Red Hat Enterprise Linux 9. On Linux the processor can be x64 or ARM.
- Nothing to install first: the download carries its own .NET.
- The server must be able to reach
login.microsoftonline.comandapi.businesscentral.dynamics.comover HTTPS, and your customers must be able to reach the server on port 443.
A web address and a certificate
- A web address for the portal, such as
portal.example.com, that points at the server. - A certificate for that address, or a reverse proxy that already has one. Section 4 covers both.
The portal's own Microsoft Entra app
The portal signs in to Business Central as an app of its own, not as a person. Register that app in the Microsoft Entra admin center:
- App registrations, then New registration. Give it a name such as
Essential Rental Customer Portal, choose Accounts in this organizational directory only, and leave the redirect URI empty. - On the app's Overview, note the Application (client) ID and the Directory (tenant) ID.
- Certificates & secrets, then New client secret. Copy the secret's Value at once, because it is shown only once, and note the date it expires.
- API permissions, Add a permission, Dynamics 365 Business Central, Application permissions. Tick
API.ReadWrite.All, choose Add permissions, then Grant admin consent.
The app in Business Central
Business Central has to be told about the app and what it may do.
- Search for Microsoft Entra Applications and choose New.
- In Client ID, enter the Application (client) ID you noted.
- Fill in Description, for example
Essential Rental Customer Portal. - Set State to Enabled.
- Under User Permission Sets, add
H2B CUSTOMER PORTALand nothing else. That set opens the portal's own pages in Essential Rental to the app, and no others.
The environment name
The name of the Business Central environment the portal will read, for example Production. The Business Central admin center lists your environments.
An email account in Business Central
Business Central sends the portal's emails: the sign-in codes and the invitations. Have an email account set up in Business Central for them to come from. Section 6 assigns it.
Have these four to hand
- Tenant ID
- The Directory (tenant) ID from the app's Overview in Entra.
- Environment name
- From the Business Central admin center.
- Client ID
- The Application (client) ID from the app's Overview in Entra.
- Client secret
- The Value you copied when you made the secret.
2 Install on Windows Server
Skip this section if the portal will run on Linux.
Extract the win-x64 zip and move the folder inside it to C:\EssentialRentalPortal, so that the program is C:\EssentialRentalPortal\EssentialRentalPortal.exe. Do not keep it inside a user's own folders, such as Downloads or the Desktop: the script closes the folder to ordinary users.
Then open PowerShell with Run as administrator and run the install script:
PowerShell, as administrator
cd C:\EssentialRentalPortal
powershell -ExecutionPolicy Bypass -File .\install\install.ps1
The script ends with The Essential Rental Customer Portal is installed and running., then the address the portal listens on, which is http://localhost:5080 for now, and the latest setup-code line from the portal's log. Section 5 uses the setup code.
What the script did
- Cleared the "downloaded from the internet" mark on the files.
- Created the service
EssentialRentalPortal, which starts with Windows and is restarted if it stops unexpectedly. - Set the service to run as its own account,
NT SERVICE\EssentialRentalPortal, which has no password to manage. - Gave that account the folder, and removed everyone's access to it except administrators and the system. The folder holds the settings and the keys that encrypt the secrets in them.
- Registered the source
EssentialRentalPortalin the Application event log. - Started the service and checked that it stayed running.
To check the service at any time, run Get-Service EssentialRentalPortal. The script is safe to run again, and running it again is how an update is finished (section 7).
If the script says the portal was installed but did not start, the reason is in the newest file in the logs folder and in the Windows event logs. Section 8 has more.
3 Install on Linux
Skip this section if the portal runs on Windows.
Unzip the download, move its folder to /opt/essential-rental-portal, and run the install script. On an ARM server the zip is named linux-arm64: use that name in place of linux-x64.
Before a second attempt, delete any folder already extracted here and any zip of another version: the commands below take every EssentialRentalPortal-*-linux-x64 they find.
If the server has no unzip, install it first with sudo apt-get install unzip or sudo dnf install unzip.
A terminal on the server, in the folder holding the zip
unzip EssentialRentalPortal-*-linux-x64.zip
sudo mv EssentialRentalPortal-*-linux-x64 /opt/essential-rental-portal
sudo sh /opt/essential-rental-portal/install/install.sh
The script ends with The Essential Rental Customer Portal is installed and running., then the address the portal listens on, which is http://localhost:5080 for now, and the latest setup-code line from the portal's log. Section 5 uses the setup code.
The one library the server must have
The portal needs the ICU library. When it is missing, the script stops and says so. Install it, then run the script again.
A terminal on the server: Debian or Ubuntu
sudo apt-get install libicu-dev
A terminal on the server: Red Hat, Fedora, Rocky or Alma
sudo dnf install libicu
What the script did
- Created the account
essentialrental, which cannot log in. - Gave that account the folder and closed the folder to other accounts.
- Wrote the systemd unit
essential-rental-portal. It starts the portal at boot and restarts it if it fails. The portal cannot gain privileges, can write only in its own folder, and may listen on ports below 1024. - Enabled and started the unit.
To check the service at any time, run systemctl status essential-rental-portal. The script is safe to run again, and running it again is how an update is finished (section 7).
The folder must be one the account can reach, so not under /home. The script refuses a path with a space or another special character in it.
A server with no browser
First-run setup (section 5) is a web page. On a server with no browser, do one of these:
- Set up HTTPS first (section 4), then open setup from your own computer and enter the setup code.
- Or tunnel to the server with the command below, and open
http://localhost:5080/setupon your own computer. Through the tunnel, your computer counts as the server itself.
A terminal on your own computer
ssh -L 5080:localhost:5080 you@your-server
A Linux without systemd
The install script needs systemd and stops without it. The portal itself does not: it is one program, EssentialRentalPortal, which runs until it is stopped and keeps everything in its own folder. Start it with whatever the system uses to keep a program running, as an account that owns the folder and is not root. Without systemd, an account that is not root cannot listen on port 443, so use route B in section 4. The rest of this page then applies, apart from the systemctl and journalctl commands. The macOS download is the same: it has no install script.
4 HTTPS
Your customers must reach the portal over HTTPS, and the portal holds you to it: it refuses to listen on a plain http:// address other than localhost. There are two routes. Choose one.
- The portal serves HTTPS itself. You give it a certificate file. Nothing else runs in front of it.
- Behind a reverse proxy. A web server you already run, such as IIS, nginx or a Synology NAS, holds the certificate and passes requests on to the portal. Choose this when that server already answers on port 443.
Route A: the portal serves HTTPS itself
The certificate is a .pfx file with its password, or the two .pem files Let's Encrypt writes, fullchain.pem and privkey.pem. Keep it in a folder named certificate inside the portal's folder, where the portal's account can read it.
Windows
Make the folder C:\EssentialRentalPortal\certificate and copy the .pfx into it. Copy it, do not move it: a moved file keeps the access rules of the place it came from, and the portal's account may not be able to read it. Then tell the portal its address and its certificate, using your file's name in place of portal.pfx, and restart it:
PowerShell, as administrator
cd C:\EssentialRentalPortal
.\EssentialRentalPortal.exe configure --listen https://portal.example.com --certificate certificate\portal.pfx --password 'your-pfx-password'
Restart-Service EssentialRentalPortal
Keep the single quotes: inside double quotes PowerShell changes a $ or a backtick in the password.
The install script does not open the firewall. Allow the portal's port through it:
PowerShell, as administrator
New-NetFirewallRule -DisplayName "Essential Rental Customer Portal" -Direction Inbound -Protocol TCP -LocalPort 443 -Action Allow
Linux, with a Let's Encrypt certificate
Let's Encrypt keeps privkey.pem where only root can read it. So first copy both files into the portal's folder and give them to the portal's account:
A terminal on the server
sudo mkdir -p /opt/essential-rental-portal/certificate
sudo cp -L /etc/letsencrypt/live/portal.example.com/fullchain.pem /etc/letsencrypt/live/portal.example.com/privkey.pem /opt/essential-rental-portal/certificate/
sudo chown -R essentialrental:essentialrental /opt/essential-rental-portal/certificate
sudo chmod 600 /opt/essential-rental-portal/certificate/fullchain.pem /opt/essential-rental-portal/certificate/privkey.pem
Then tell the portal its address and its certificate, and restart it. Run configure as the portal's account, as shown, so that its check proves that account can read the files:
A terminal on the server
sudo -u essentialrental /opt/essential-rental-portal/EssentialRentalPortal configure --listen https://portal.example.com --certificate /opt/essential-rental-portal/certificate/fullchain.pem --key /opt/essential-rental-portal/certificate/privkey.pem
sudo systemctl restart essential-rental-portal
The install script does not open the firewall. If the server has one, open port 443 in it.
What configure does
configure checks that the certificate loads before it saves anything. It then saves the settings in portal.settings.json, with the password encrypted, and says what it saved: the address, and the certificate with the date it is valid until. When something is wrong it says what, and saves nothing.
After the restart the portal answers at https://portal.example.com, and no longer at http://localhost:5080. If it does not start, the newest file in its logs folder says why (section 8).
Both kinds of certificate work on both systems: name a .pfx with --certificate and --password, or .pem files with --certificate and --key.
When the certificate is renewed
Replace the file or files under the same names, by copying, not moving. The portal serves the new certificate within about a minute, with no restart.
For Let's Encrypt, a renewal hook does the copying. Save this as /etc/letsencrypt/renewal-hooks/deploy/essential-rental-portal.sh:
The file /etc/letsencrypt/renewal-hooks/deploy/essential-rental-portal.sh
#!/bin/sh
cp -L /etc/letsencrypt/live/portal.example.com/fullchain.pem /etc/letsencrypt/live/portal.example.com/privkey.pem /opt/essential-rental-portal/certificate/
chown essentialrental:essentialrental /opt/essential-rental-portal/certificate/fullchain.pem /opt/essential-rental-portal/certificate/privkey.pem
chmod 600 /opt/essential-rental-portal/certificate/fullchain.pem /opt/essential-rental-portal/certificate/privkey.pem
Then mark it executable:
A terminal on the server
sudo chmod +x /etc/letsencrypt/renewal-hooks/deploy/essential-rental-portal.sh
A .pfx whose password has changed is the one case that needs more: run configure again with --certificate and --password, then restart the portal.
Route B: behind a reverse proxy
The portal stays on http://localhost:5080, which is how the install script left it. When the proxy runs on the same server there is nothing to configure in the portal.
The proxy must:
- hold the certificate for
portal.example.com, and pass every request tohttp://localhost:5080; - send
X-Forwarded-Forwith the visitor's address, which the proxy adds itself. A proxy that passes on whateverX-Forwarded-Forthe visitor sent lets the visitor choose the address the portal records; - send
X-Forwarded-Protowith the valuehttps; - pass the
Hostheader through unchanged.
With these, the portal marks its sign-in cookie Secure, sends HSTS, and records each visitor's own address.
nginx
nginx: a server block in its configuration
server {
listen 443 ssl;
server_name portal.example.com;
ssl_certificate /etc/letsencrypt/live/portal.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/portal.example.com/privkey.pem;
location / {
proxy_pass http://localhost:5080;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
IIS
IIS needs two additions installed, URL Rewrite and Application Request Routing. Then, in IIS Manager:
- At the server, open Application Request Routing's Server Proxy Settings and tick Enable proxy. Application Request Routing adds the visitor's address to
X-Forwarded-Foritself. - Have IIS pass the
Hostheader through: open Configuration Editor at the server, choose the sectionsystem.webServer/proxy, and setpreserveHostHeadertoTrue. - In URL Rewrite, choose View Server Variables and add
HTTP_X_FORWARDED_PROTOto the allowed server variables. - Give the site an HTTPS binding for
portal.example.com. The rule below passes on only requests that arrived over HTTPS, so a visit over plain HTTP never reaches the portal: IIS answers it itself, usually with its own "not found" page. If the site also has an HTTP binding, remove it, or add a redirect to HTTPS in IIS if you want such visits to end up on HTTPS. - Save this as the site's
web.config.
The site's web.config
<configuration>
<system.webServer>
<rewrite>
<rules>
<rule name="Essential Rental Customer Portal" stopProcessing="true">
<match url="(.*)" />
<conditions>
<add input="{HTTPS}" pattern="^on$" />
</conditions>
<serverVariables>
<set name="HTTP_X_FORWARDED_PROTO" value="https" />
</serverVariables>
<action type="Rewrite" url="http://localhost:5080/{R:1}" />
</rule>
</rules>
</rewrite>
</system.webServer>
</configuration>
A Synology NAS
In DSM, open Control Panel, Login Portal, Advanced, Reverse Proxy, and choose Create.
- Source: HTTPS,
portal.example.com, port443. - Destination: HTTP,
localhost, port5080. - On the rule's Custom Header tab, make sure
X-Forwarded-Foris sent with the value$proxy_add_x_forwarded_for, andX-Forwarded-Protowith the value$scheme.
Check the proxy
Whichever proxy you use, ask the portal for its sign-in page through it:
A terminal on another computer
curl -sI https://portal.example.com/sign-in
Look in the answer for a Strict-Transport-Security line, which some proxies show in lower case. It means the portal knows the visitor is on HTTPS. The first line of the answer does not matter: this command asks for the headers alone, which the portal answers with 302 until first-run setup is done and with 404 afterwards. No such line means the proxy is not sending X-Forwarded-Proto, or is not a proxy the portal believes.
Do this check before first-run setup is finished and before the address is public: until the Strict-Transport-Security line appears, a visitor through the proxy can look like the server itself.
A proxy on another machine, or a network in front
The portal believes a proxy on its own machine, and nobody else. A proxy on another machine, or a network such as Cloudflare's in front of your proxy, has to be listed before the portal believes what it says about the visitor. Until it is, the portal records that proxy's or network's address as the visitor's.
Windows: PowerShell, as administrator, in C:\EssentialRentalPortal
.\EssentialRentalPortal.exe configure --trusted-proxies "192.168.1.5"
Restart-Service EssentialRentalPortal
Linux: a terminal on the server
sudo -u essentialrental /opt/essential-rental-portal/EssentialRentalPortal configure --trusted-proxies "192.168.1.5"
sudo systemctl restart essential-rental-portal
- The list is addresses and networks separated by commas, such as
192.168.1.5,173.245.48.0/20. Each time, give the whole list: it replaces the one before. - For Cloudflare, list every range Cloudflare publishes at https://www.cloudflare.com/ips/.
- The portal reads the list when it starts, so restart it after every change.
- A proxy on another machine reaches the portal over the network, and the portal listens beyond
localhostonly over HTTPS. That arrangement therefore needs route A as well: a certificate in the portal, with the proxy passing requests to itshttps://address. A proxy on the same server is the simple arrangement.
5 First-run setup
Setup is one page, where you connect the portal to Business Central. It is protected by a setup code.
The setup code
The portal makes a new 8-digit setup code every time it starts, and writes it to its log. The install script showed you the one from that start. If the portal has been restarted since, as section 4 does, the code has changed. To see the latest:
Windows: PowerShell, as administrator
Select-String -Path C:\EssentialRentalPortal\logs\portal-*.log -Pattern "setup code" | Select-Object -Last 1
Linux: a terminal on the server
sudo sh -c 'grep -h "setup code" /opt/essential-rental-portal/logs/portal-*.log | tail -n 1'
The line ends with the code.
Open setup
Open the portal's address followed by /setup.
- On the server itself, at
http://localhost:5080/setup, and before setup is finished, the page opens directly. - Opened any other way, and always once setup is finished, it asks for the setup code first.
- Ten wrong codes close setup until the portal is restarted, which also makes a new code.
Connect to Business Central
- Enter the four values from section 1:
Tenant ID,Environment name,Client ID of the portal's Entra appandClient secret. - Choose
Test connection. The page answersConnected.and lists the companies in the environment, with each one's licence and whether the portal is switched on there. Until you have done section 6, every company readsSwitched off, and that is expected. If the page saysThe connection did not work:, the reason follows: check the four values, the admin consent in Entra, and the app's card in Business Central. - Leave
Listen addressas it is: it is the address the portal was installed with, or the one you set in section 4. - Choose
Finish setup. The portal's sign-in page opens, and setup is done.
Connect the customer portal to Business CentralBusiness CentralTenant IDaaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeeeEnvironment nameProductionClient ID of the portal's Entra app11111111-2222-3333-4444-555555555555Client secret••••••••••••••••CompaniesCompanyCustomer Portal licencePortal in Business CentralMain companyLicensedSwitched onMain companyListeningListen addresshttps://portal.example.comLeave Developer mode off. Everything else about the portal is set in Business Central, which is the next section.
When the client secret is about to expire
Make a new secret in Entra, as in section 1. Open setup with the setup code, enter the new secret in Client secret, and choose Save. The portal uses it within a minute, with no restart.
6 Finishing in Business Central
Do this in each company the portal serves.
The setup wizard
Search for Customer Portal Setup, which is also on the Essential Rental Setup page, and choose Setup Wizard. After its welcome page, its steps are:
- The portal address. In Portal Address, enter the address your customers will type, such as
https://portal.example.com. Invitation emails show it. - The email account. Use Choose Email Account. Portal emails come only from the account assigned to the Customer Portal email scenario, never from your default account.
- How the portal looks. The two brand colours, and the Main Company and Show Powered By settings. When the portal serves several companies, tick Main Company in the one whose name and logo belong on the sign-in page.
- Send a test email. Choose Send Test Email, and check that it arrives. The first time, Business Central may ask you to allow the connection.
- Finish, which is available once the test email has been sent. It switches the portal on for this company and starts the job that sends portal emails.
That job is a job queue entry that sends every minute and runs as you, the person who finished the wizard. So your user needs the right to send from the email account you chose.
Portal users
People are given access customer by customer.
- On a customer's card, choose Portal Users, then Invite.
- Enter the person's Full Name and Email. Business Central emails them an invitation within about a minute, and the portal picks up a new person in about the same time.
- They open the portal and sign in with a code sent to that address. There is no password.
Can See Billing decides, for each person and customer, whether that person sees balances and invoices. It is off until you tick it.
Is it working?
Customer Portal Setup shows both halves. Under Email, Sender Job says whether portal emails are going out. Under Portal Website, Last In Touch says when the portal last reported. The portal reports every 15 minutes, so a newly installed portal can take that long to appear.
7 Updating, backing up, moving and uninstalling
Updating
When Essential Rental and the portal both have a new version, update Essential Rental in Business Central first. Then update the portal. Your settings, data and logs are not in the zip, so they stay as they are.
Windows
- In PowerShell, as administrator, run
Stop-Service EssentialRentalPortal. - Extract the new zip, and copy everything in the folder it extracts over the files in
C:\EssentialRentalPortal. Copy from that folder only: anything left from an earlier version's zip is the old program. - Run
install.ps1again, as in section 2. It starts the service.
Linux
Download the new zip into an empty folder, or first delete the earlier zip and any folder extracted from it. The commands below take every EssentialRentalPortal-*-linux-x64 they find.
A terminal on the server, in a folder that holds the new zip and nothing from an earlier version
sudo systemctl stop essential-rental-portal
unzip EssentialRentalPortal-*-linux-x64.zip
sudo cp -a EssentialRentalPortal-*-linux-x64/. /opt/essential-rental-portal/
sudo sh /opt/essential-rental-portal/install/install.sh
Backing up and moving
Everything the portal keeps is in its folder: portal.settings.json, data (the database, the keys that encrypt the secrets, and cached files) and logs. To back it up, stop the service, copy the folder, and start the service.
Linux: a terminal on the server
sudo systemctl stop essential-rental-portal
sudo tar -czf /root/essential-rental-portal-backup.tar.gz -C /opt essential-rental-portal
sudo systemctl start essential-rental-portal
The portal's data is a copy of what Business Central holds. A lost portal can be installed afresh, and will read it all again.
Moving to another server
Copy the whole folder to the new server, run the install script there, and point the web address at the new server.
- From Linux to Linux, everything comes with the folder.
- Between Windows servers, the secrets do not: they are tied to the server they were saved on. If the portal serves HTTPS itself from a
.pfx, the install script on the new server therefore saysThe portal was installed but did not start.and stops. That is expected: runconfigureagain with--certificateand--password, as in section 4, thenRestart-Service EssentialRentalPortal. Then, whichever way the portal serves HTTPS, open setup with the setup code and enter the client secret again.
Uninstalling
Windows: PowerShell, as administrator, in C:\EssentialRentalPortal
powershell -ExecutionPolicy Bypass -File .\install\uninstall.ps1
Linux: a terminal on the server
sudo sh /opt/essential-rental-portal/install/uninstall.sh
Either script removes the service and leaves the settings, data and logs where they are. On Linux the account essentialrental stays too. Delete the folder to remove the rest and, on Linux, remove the account with sudo userdel essentialrental.
8 Troubleshooting
Where the logs are
In logs, inside the portal's folder. There is one file a day, named portal- and the date, and 30 days are kept. On Windows, warnings and errors are also in the Application event log under EssentialRentalPortal. On Linux, the journal has them too:
Linux: a terminal on the server
sudo journalctl -u essential-rental-portal -n 50
The service will not start
The last line of the newest log file says The portal did not start. and then why. The usual reasons:
- An
https://listen address with no certificate set. Set one withconfigure(section 4). - A certificate file that is missing, or that the portal's account cannot read. On Windows, running
install.ps1again resets the access rules on everything in the folder. On Linux, section 4 has the commands that give the files to the account. - A slip in
portal.settings.jsonafter it was edited by hand. The message says where. Correct the file itself:configurewill not write over a settings file it cannot read. - Another program already holds port 443, as a web server on the same machine does. The log then shows an error in place of that line, usually one that names the address and says it is already in use. Use route B (section 4), or free the port.
Fix the cause, then start the service again: Restart-Service EssentialRentalPortal on Windows, sudo systemctl restart essential-rental-portal on Linux.
configure will not save
When configure cannot use what it was given, it says what is wrong and saves nothing. It never repeats the password, and when an option is mistyped its message names the option and not what followed it.
- An option takes its value after a space, not after
=. Put a value that has a space in it in quotes. Nothing was saved:followed by a file or folder it may not touch means the command was run as the wrong account. On Windows, run it as an administrator. On Linux, run it as the portal's account, withsudo -u essentialrental, as section 4 shows.- On Linux,
configurerun as root does save, but leaves files the service cannot write. Runninginstall.shagain repairs that.
A lost setup code
The code is written to the log at every start, and section 5 has the command that finds it. Restarting the portal makes a new one, which is also the way out when setup says there were too many wrong codes.
Sign-in emails do not arrive
In Business Central, Customer Portal Setup says why under Email, and its Email Queue shows what went out and what is waiting.
- If Sender Job says it is not set up or not running, or the job was deleted, run the Setup Wizard again. It creates or restarts the job.
- If it stopped with an error, open Job Queue Entries and use Run once (foreground) on the entry "Send Customer Portal emails", so that Business Central can ask for what it needs. Then run the Setup Wizard again to restart the job.
"The portal hasn't been in touch"
Business Central says this when the portal has been silent too long. Check that the service is running, that the server can reach the internet, and that the client secret has not expired (section 5).
The connection is not secure, or sign-in will not stick
Behind a proxy, run the check in section 4: the proxy must send X-Forwarded-Proto. On IIS, also check that the request reached the site over HTTPS (section 4). The portal ignores the setting ASPNETCORE_FORWARDEDHEADERS_ENABLED, which some guides say to turn on, and says so once in its log. When the portal serves HTTPS itself, its log names the certificate it serves and the date it is valid until, and warns when it has expired.
A browser still shows the old colours
A new brand colour shows at once. If something in front of the portal, such as a proxy's or a network's cache, still serves the old page, clear that cache.