How Odoo Keycloak SSO works for a self-hosted instance
The usual route for signing staff into a self-hosted Odoo instance with Keycloak identities is the OCA auth_oidc module, which runs an OpenID Connect authorization code flow against a Keycloak realm. Odoo's Community edition on GitHub is licensed under LGPL-3.0, and Keycloak is licensed under Apache 2.0, so the two components can be combined in a self-hosted stack without a license conflict that this page is aware of. Confirm the license terms of any specific module version you adopt, since auth_oidc is a separate community project with its own repository and license file.
auth_oidc is a community module published by the Odoo Community Association, not a component of Odoo itself. Before planning the work, confirm that the module branch matches your Odoo major version, because the module's manifest, controllers and login templates change between releases. A branch built for an older version may load but fail at the callback step, and a branch for a newer version may depend on framework APIs your instance does not have. Ask whoever maintains the module to show the version matrix, then test the branch on a copy of your database before it reaches production.
Odoo also documents its own sign-in options, including LDAP with optional user creation on first login, Google Sign-In, Microsoft Azure OAuth and Facebook sign-in. These are separate code paths from auth_oidc. Enabling LDAP does not make Keycloak the identity source for Odoo, and enabling Azure OAuth does not route Keycloak logins through Odoo. Decide which path is authoritative for staff accounts before configuration starts, because running two sign-in methods against the same users creates duplicate or conflicting accounts.
The scope of this section is sign-in and user matching. The module redirects a user to Keycloak, receives an authorization code, exchanges it for tokens at the token endpoint, validates the ID token signature against the keys published at the JWKS endpoint, and then maps the verified identity to an Odoo user. The matching rule, usually the email claim or a subject identifier, decides whether a login attaches to an existing Odoo user or fails. Choose the matching attribute with your identity team, verify that it is unique and stable in the Keycloak realm, and decide what happens when a Keycloak user has no matching Odoo account.
Role assignment, group-based access, provisioning of new users and payment flows are outside what this section covers, and the auth_oidc module should not be assumed to handle them. Ask the module maintainer and your Odoo partner to state in writing which user attributes the module reads and writes, which Odoo access rights remain managed inside Odoo, and how a disabled Keycloak account is reflected in Odoo sessions. These answers determine the test plan and the operating runbook for the integration.
Prerequisites for Odoo Keycloak SSO
These prerequisites set the boundaries for the Odoo and Keycloak SSO build. Each item is a decision or check that shapes the next step, from the Odoo version and plan to the redirect URI and the OIDC module branch. Confirm each one in writing before configuration starts so the Keycloak client and the Odoo settings match.
Supported Odoo version and plan
Start from an Odoo major version that still receives security updates. Standard support for 19.0 runs to September 2028 and for 18.0 to September 2027, while standard support for 17.0 ended in September 2026. Odoo's pricing page lists the Custom plan as the only plan that can be hosted on Odoo.sh or on-premise, so a self-hosted design requires it. Confirm the plan and the support end date with Odoo before you commit to the architecture, because later upgrades depend on both.
Keycloak release and production database
Use a current Keycloak release, such as 26.8.1, published October 13, 2026, and pair it with a supported production database. The Keycloak database guide lists PostgreSQL 14 to 18 among the supported options. The default dev-file database is for development only, so a proof of concept built on it is not a production foundation. Decide the database, its backups and its high availability model before you configure clients, because realm settings and user records are stored there.
DNS names and trusted TLS certificates
Give Odoo and Keycloak stable DNS names that resolve from every network where users sign in, and issue TLS certificates that both systems trust. Browsers redirect users between Odoo and Keycloak, while the Odoo server calls Keycloak's token and JWKS endpoints directly. If you use an internal certificate authority, the Odoo host must trust its chain as well as user devices. Test the chain from the Odoo application server itself, and plan certificate renewal before go-live.
Agreed redirect URI
Fix the redirect URI in the Keycloak client before anyone configures Odoo. It must match the callback address Odoo sends during the authorization code flow, including scheme, host, port and path. Confirm the callback path that the OCA auth_oidc module uses in your exact Odoo version, and record the base URL Odoo presents when it sits behind a reverse proxy or load balancer. A mismatch stops sign-in before any user reaches the Odoo login screen.
OCA auth_oidc branch and dependencies
Select the auth_oidc branch in the Odoo Community Association repository that matches your exact Odoo version, and confirm its module and Python dependencies against that version. Do not assume a branch built for one major version works on another. Review the module's license, open issues and recent activity, then test it in a copy of the production database. Record the commit you deploy so that upgrades can repeat the same choice.
How Keycloak tokens and JWKS keys are checked at Odoo login
Every Odoo sign-in through Keycloak runs the same chain of steps, and a misconfiguration at any one of them stops login or, worse, lets it succeed for the wrong reason. The chain starts when a user clicks the Keycloak sign-in button on the Odoo login page. Odoo, through the OCA auth_oidc module, redirects the browser to the Keycloak authorization endpoint with the client identifier, the requested scopes, a state value and the redirect URI registered for that client. Keycloak authenticates the user in the realm, which may include a second factor, and then sends the browser back to Odoo with a short-lived authorization code. The next step happens server to server. Odoo posts the authorization code to the token endpoint along with the client identifier and client secret, and receives an ID token and, usually, an access token in return. If the client secret is wrong, the Keycloak client is set to a different client authentication method than Odoo expects, or the redirect URI in the token request does not exactly match the one registered in Keycloak, the exchange fails and the user sees an error after being sent back from Keycloak. Confirm the client authentication method and the exact redirect URI string in both systems before testing, since a trailing slash or an http scheme mismatch is enough to break the exchange. Before Odoo trusts the ID token, it validates the token itself. The signature is checked against the public keys published at the JWKS endpoint, and the key is selected using the key identifier in the token header. Odoo then checks the issuer claim against the issuer it was configured with, the audience claim against its client identifier, and the expiry and issued-at times against its clock. If the issuer is taken from a stale or internal hostname, if the audience does not include the Odoo client, or if the server clock drifts, valid logins will fail. Rotating Keycloak realm keys without Odoo being able to fetch the new JWKS is a common cause of sudden, widespread sign-in failures. The discovery document, normally found at the realm's well-known OpenID configuration path, is the usual way to obtain the authorization, token and JWKS endpoints and the issuer value, so the configuration does not have to copy each URL by hand. Check that the issuer in the discovery document matches the issuer Odoo validates against, including the public hostname Keycloak advertises behind a reverse proxy. Confirm with the version of auth_oidc you are deploying which endpoints it reads from discovery, which claims it maps to Odoo users, and whether it checks the audience and the at_hash or nonce values, because these behaviors differ between releases. Plan tests that break each step on purpose: a wrong secret, a changed redirect URI, a rotated signing key, an expired token and a clock offset. Each failure should produce a recognizable log entry on the Odoo side and on the Keycloak event log, so your operations team can tell a configuration fault from a directory or network fault during an incident.
Odoo Keycloak SSO setup sequence
This sequence takes a self-hosted Odoo database from a dedicated Keycloak realm to a tested single sign-on login. Each step ends with a check you can verify before moving on, so problems surface in the realm, client, or test database rather than in production.
Create a dedicated Keycloak realm
The Keycloak administrator creates or selects a realm for Odoo users, kept separate from the administrative realm. Confirm that the OpenID discovery document for that realm loads over HTTPS from a browser and from the Odoo server, because both need to reach the same issuer. Check that the document reports the issuer URL you expect and that its authorization, token, userinfo and JWKS endpoints all use your public HTTPS hostname. If any endpoint shows an internal hostname, correct the realm's frontend URL before creating clients.
Register a confidential OIDC client
In the realm, create an OpenID Connect client with client authentication enabled so that it is confidential. Turn on the standard authorization code flow and leave implicit and direct grant flows off unless you have a documented need for them. Register the exact redirect URI that the OCA module expects on your Odoo hostname, matching scheme, port and path as shown in that module's documentation for your Odoo version. Teams managing Keycloak on Kubernetes can declare this client with the KeycloakOIDCClient resource from the Keycloak Operator, so the definition lives in version control. Set operator updates to manual approval mode, as the Keycloak documentation recommends. Check that the client shows a generated client secret and that a test authorization request reaches the Keycloak login page without a redirect URI error.
Define scopes and claims and test a token
Confirm that the openid, profile and email scopes are assigned to the client. Add protocol mappers only for claims Odoo needs to match or create users, such as the login, email and display name. Sign in as a Keycloak test user through a client tool that performs the authorization code flow, then decode the ID token. Check that the ID token contains the subject and the claim you chose as the Odoo login, and that the token's signing key appears in the JWKS document, which Odoo uses to verify signatures. If a claim is missing, fix the mapper here, because the later user matching depends on it.
Install the OCA auth_oidc module on a test database
The Odoo administrator installs the OCA auth_oidc module from the Odoo Community Association repository, using the branch that matches the Odoo version in use, and places it on the addons path. Use a non-production copy of the database so that a failed install or a misconfigured login cannot affect live users. Restart the Odoo server, update the apps list, and search for the module. Check that the module appears in the module list with the expected version and installs without errors in the server log.
Enter the provider settings and check the login button
In the test database, open the OAuth provider configuration that the module adds, and enter the issuer URL, client ID and client secret from Keycloak. Enter the authorization, token, userinfo and JWKS endpoints from the discovery document, and set the scopes to match the mappers defined earlier. Store the client secret only in the provider record or in your approved secrets process, and confirm the menu path in your Odoo version's documentation. Save the record and open the Odoo login page in a private browser window. Check that the Keycloak login button renders on the sign-in screen.
Test login and confirm user matching
Sign in with a Keycloak test user who has no Odoo account, then sign in with a test user who already has one. Confirm whether the module matches the existing record on the login or email claim, and whether it creates a new user on first login from the template you configured. Check the groups, company and access rights assigned to each user, since these come from your configuration and not from Keycloak by default. Check that the new user is created as configured and that the existing user lands in the correct record with only the access rights you intended. Record these results so the same test can be repeated before any production change.
Keycloak claims mapped to Odoo user fields
This table compares each Keycloak claim with the Odoo user field it fills and whether Odoo needs it to match a returning user. Read the required rows first, because matching fails or creates duplicate accounts when those values are missing, unverified or not unique.
| Keycloak claim | Odoo field | Required for matching | Notes |
|---|---|---|---|
| sub (subject) | Stable external identifier stored with the user | Required | Keycloak's internal user ID is the most stable key. Confirm the exact claim name and how your auth_oidc version stores it. |
| preferred_username | Login | Optional | Usable as login only if unique and stable in Keycloak. Renaming a Keycloak user can break matching if login is the key. |
| email (with email_verified) | Email and login matching | Required if matching on email | Only trust it when email_verified is true. Odoo emails must also be unique, or two users may match one identity. |
| given_name | Name (first part) | Optional | Display only. Changes in Keycloak update the Odoo name only if your module syncs on each login. |
| family_name | Name (last part) | Optional | Display only. Names with multiple parts or local scripts need a decision on how they split into the Odoo name. |
| groups or roles (if emitted) | Odoo groups via mapping | Optional | Mapping is a team decision. Odoo groups and access rights stay managed in Odoo unless you build that sync. |
| Account creation on first login | New user template | Not a claim | Decide whether unknown users are created and which Odoo template sets their default groups before go-live. Confirm this option with your module version. |
| Exact claim names and scopes | Configuration in Keycloak client and Odoo | Not a claim | Confirm the names your chosen OCA auth_oidc version reads, and which scopes the Keycloak client must release, before building the mapping. |
Security settings for Keycloak sign-in to Odoo
Signing users into Odoo through Keycloak moves the trust decision to the identity provider, so both systems need to be configured as one controlled chain. The cards below cover the client credentials, the redirect and token checks, transport encryption, session and second-factor decisions, role scoping and logging that together determine who can reach Odoo and how that access is recorded.
Confidential client and rotated secret
Register Odoo as a confidential client in the Keycloak realm so the client secret is required at the token endpoint. Store the secret in an environment variable or a secrets manager outside the Odoo source tree and the database, and rotate it on a schedule your team can actually run. Confirm during testing that the old secret stops working after rotation and that no logs or configuration exports contain it.
Exact redirect URI matching
Configure the Keycloak client with the full callback URL of each Odoo database and environment, and disable wildcards and open-ended patterns. A loose redirect URI lets an attacker steer authorization codes to a host they control. Review the list whenever a new database, staging copy or custom domain is added, because each one becomes an accepted destination.
TLS on both sides
Serve Keycloak and Odoo only over HTTPS, and confirm that Odoo can validate the Keycloak certificate chain when it calls the token and JWKS endpoints. Check that internal certificate authorities are trusted by the Odoo host, not disabled through verification flags. Mixed-content redirects and plain HTTP callbacks are common causes of leaked codes and should be tested explicitly.
Token signature and audience validation
Verify that Odoo checks the signature of the ID token against the realm keys published at the JWKS endpoint, and that it rejects tokens whose issuer or audience does not match the client it expects. Test with a token issued to a different client in the same realm to confirm rejection. Confirm the accepted signing algorithms in the module configuration against what the realm actually issues.
Session lifetimes and production settings
Set short access token and SSO session lifetimes in the Keycloak realm, balanced against how often users can tolerate re-authentication. Apply the production configuration guidance from the Keycloak documentation for hostname, proxy headers and HTTP settings, rather than running the development defaults. Record the chosen values, since they determine how long a revoked user can still hold an active Odoo session.
Break-glass local administrator
Keep at least one local Odoo administrator account that does not depend on Keycloak, so the team can recover access if the identity provider is unavailable or misconfigured. Protect it with a strong password, store it in a sealed process, and protect it with two-factor authentication, which Odoo documents. Test the procedure in a non-production copy and log every use of the account.
Second factor placement
Odoo documents two-factor authentication, and Keycloak can also enforce a second factor during sign-in. Decide which system enforces it for SSO users, then confirm that users do not see duplicate prompts and that no path, such as the local login form or the break-glass account, skips the required factor. Document the decision so administrators do not change one side and weaken the other.
Realm role restrictions
Map only the Keycloak realm roles that should reach Odoo to an Odoo group, and deny sign-in for users without one of those roles at the client level. Review role mappers so that broad realm roles do not silently grant Odoo administrator rights. Ask your team to confirm how new roles are added and who approves changes to these mappings.
Sign-in event logging in both systems
Enable logging of login successes, failures and token-related errors in Keycloak, and record Odoo authentication events and user creation on first login in the Odoo log. Correlate the two by user identifier and timestamp so that investigators can trace a single session across both systems. Confirm where the logs are shipped, how long they are kept, and who can read them.
Common Odoo Keycloak SSO failures and fixes
This table lists the sign-in failures most often seen when Odoo uses Keycloak through the OCA auth_oidc module, with the likely cause and the first check for each. Work down the rows in order when a sign-in fails, since the first check often rules out several causes at once. The main takeaway is that most failures come from a mismatch between what Keycloak advertises and what Odoo has configured, so compare those values before changing anything else.
| Failure | Likely cause | First check |
|---|---|---|
| Redirect URI mismatch | The Odoo base URL or database parameter in the callback differs from the valid redirect URI registered on the Keycloak client. | Compare the URI in the Keycloak client with the callback URL shown in the browser error, including scheme, port and path. |
| Issuer mismatch | Configured issuer differs from the discovery document issuer, often because a proxy changes the hostname or trailing slash. | Fetch the realm's discovery document from the Odoo host and compare its issuer string character by character with the configured value. |
| JWKS fetch fails | Firewall rules or egress proxies block the Odoo server or container from reaching the keys endpoint, or the certificate chain is untrusted. | From inside the Odoo container, request the JWKS URI with curl and confirm the TLS handshake succeeds with the internal CA bundle. |
| Token expiry or not yet valid errors | Clock skew between the Keycloak host, the Odoo host and the database host, so issued-at or expiry times fall outside the allowed window. | Compare UTC time on each server and confirm NTP synchronization is active on all of them. |
| Duplicate users after sign-in | The token has no email claim, or the claim differs from the stored login, so Odoo creates a new account for the same person. | Decode a test login token and confirm the email claim is present, mapped in Keycloak and matches the Odoo login field. |
| Sign-in fails after secret rotation | The client secret was regenerated in Keycloak but the new value was not saved in the Odoo provider configuration. | Check the token endpoint response for an invalid client error and compare the secret stored in the Odoo provider record. |
| Test system accepts production users | A production database was copied without neutralizing it, so the test system still holds live users, provider settings and enabled sign-in. | Confirm the test database's OIDC provider is disabled or pointed at a non-production realm, and that user records were neutralized. |
| Sign-in breaks after Keycloak upgrade | A newer Keycloak release changed a default, for example token lifetime, client scope or redirect handling, that Odoo depended on. | Compare the upgrade notes for each release crossed with the realm and client settings exported before the upgrade. |
Testing Odoo Keycloak SSO before cutover
The test plan starts with a copy of the production database, and the first check is whether that copy can reach anything live. Odoo documents database duplication with neutralization as its method for creating a test copy. Neutralization is intended to disable scheduled actions, outgoing mail and external integrations in the copy, but you should confirm this in your Odoo version before any sign-in test runs. Inspect the outgoing mail server records, the scheduled actions and any payment or connector settings, and confirm that the Keycloak client used by the copy has a test redirect URI. A sign-in test on a copy that can still send email or sync to live systems creates real side effects for customers and staff.
Run the first four cases with named Keycloak test users, then check the resulting Odoo user record each time. For a new user, confirm whether auth_oidc creates the Odoo account on first login, which template or groups it applies, and whether the user lands with the access you expect. For an existing user matched by email, confirm the matching key and verify that a second account is not created. For a disabled Keycloak user, confirm that sign-in fails and that no Odoo session or user record is created. For an unverified email, confirm how the module treats the email claim when Keycloak reports it as unverified, and whether matching still happens. Record the exact outcome for each case so the results can be repeated later.
The remaining cases test failure paths and recovery. For a failed token exchange, use an incorrect client secret or an expired authorization code and confirm that Odoo shows a controlled error and leaves no partial user behind. For a Keycloak secret rotation, rotate the client secret in the test realm, confirm that the old secret is refused, update the Odoo configuration, and confirm that sign-in works with the new secret. For the fallback login path, confirm that a local administrator can still sign in with a password when the identity provider is unavailable, and document who holds those credentials and where they are stored. Test the fallback before cutover, because a broken SSO configuration without a working fallback can lock out every user.
Repeat this full test set after any Keycloak upgrade and after any Odoo major upgrade. Keycloak plans four minor releases a year, and its project says breaking changes in a minor release are opt-in, so a version change still needs a check of your realm, client and mapper settings. On Odoo Online and Odoo.sh, the upgrade documentation makes major version upgrades mandatory every two years, so this repeat is a recurring cost to plan for. Ask any implementation partner to state in the written scope which cases are included, who runs them, how results are recorded, and whether the repeat tests are part of a support retainer or a separate piece of work.
Questions buyers ask about Odoo Keycloak SSO
What drives the cost of Odoo Keycloak SSO integration?
Labor is the main cost, and five factors move it most: the number of Odoo databases and companies, whether the Keycloak realm already holds clean identities, whether group or role sync is required, how deep testing goes, and how often Odoo and Keycloak are upgraded. Each Odoo database needs its own client configuration and login tests, so counts multiply the work. Identity cleanup is often the hidden item, because duplicate or inconsistent accounts must be resolved before users can be matched safely. One-time work covers planning, configuration, testing and handover. Recurring work covers module maintenance, client secret rotation and retesting after each upgrade. Ask for a written scope that lists databases, companies, sync requirements, test cases and the client decisions each phase depends on.
How long does an Odoo Keycloak SSO project take?
No single duration fits every environment, so treat any fixed figure with caution. Timing depends mainly on identity cleanup in Keycloak and on the size of the test scope, not on the sign-in change itself. A realm with unused clients, duplicate users or mismatched email addresses takes longer to reconcile than a clean one. Test scope grows with each Odoo database, company, role and integration that must be verified. Client decisions also affect timing, such as who approves user matching rules and which hostname Odoo will use. Ask the partner for a written scope with phases, the test cases covered and the dependencies that could pause each phase, so the schedule follows from the agreed work.
What does our team need to provide for the SSO project?
The project needs four roles from your side. A Keycloak administrator creates the client, mappers and realm settings and confirms how identities are stored. An Odoo administrator installs and configures the module and provides access to a non-production database copy. DNS and certificate owners confirm the public Odoo hostname and the TLS chain used in redirect URIs, and they handle renewals later. Test users should cover each role, each company and each login path, including users who should be denied access. A named approver should also sign off on user matching rules, because those rules decide whether an existing Odoo account is reused or a new one is created.
Can our internal team set up Odoo Keycloak SSO alone?
Yes, if your team can run a non-production Odoo instance, configure OpenID Connect clients in Keycloak, and own secret rotation and certificate renewal. The team also needs to test after every Odoo and Keycloak upgrade, which is the part most often underestimated. Before committing, check the sign-in path itself. Odoo's documented sign-in options cover LDAP, Google Sign-In, Microsoft Azure OAuth, Facebook sign-in and two-factor authentication, and they do not list Keycloak. Connecting Keycloak therefore depends on a third-party or community module, such as the OCA auth_oidc module, or on SAML through auth_saml. The module choice and its support terms are a project decision that your team should record in writing.
Does Odoo sign in with Keycloak without a custom module?
No. Odoo's documented sign-in options do not include Keycloak. The documented options include LDAP with optional user creation on first login from a template, Google Sign-In, Microsoft Azure OAuth, Facebook sign-in and two-factor authentication. Keycloak sign-in is usually added with a community module, most often the OCA auth_oidc module for OpenID Connect, or with SAML through auth_saml. Confirm three things before choosing: that the module supports your target Odoo version, that your hosting type allows you to install it, and who supports it when an upgrade breaks it. Odoo's documentation does not describe Keycloak integration, so the module's own documentation and its maintainers are the reference for those points.
How do Odoo and Keycloak upgrades affect SSO maintenance?
Both platforms change on their own schedules, so the SSO setup needs a maintenance plan. Each Odoo major version can change authentication code paths, so the OIDC module must be checked against the target version before the upgrade. On Odoo Online and Odoo.sh, major version upgrades are mandatory every two years, which sets a recurring test window. Keycloak also releases minor versions several times a year and says that breaking changes in minor releases are opt-in. Test each upgrade on an upgraded database copy, rerun login and role tests, and review client settings and token lifetimes. Ask your partner whether maintenance is included in the initial scope or sold as a retainer.
When does SAML through auth_saml fit better than OpenID Connect?
SAML through auth_saml fits better when your identity standards already rely on SAML assertions for most applications, or when your identity team needs specific attribute mapping that is easier to manage in SAML. OpenID Connect through auth_oidc is the more common starting point for Keycloak, because Keycloak exposes OpenID Connect with the authorization code flow, token endpoints and JWKS keys that the module validates. Either choice needs the same discipline around user matching, secret or certificate rotation and upgrade testing. Decide the protocol early, because switching later means reconfiguring the identity provider, the Odoo module and the test plan. Confirm module maintenance status for your Odoo version before the decision is final.
What usually breaks in Odoo Keycloak SSO after go-live?
Most failures after go-live come from configuration drift rather than from the sign-in flow itself. Redirect URI mismatches appear after a hostname, reverse proxy or certificate change. Expired or rotated client secrets stop logins without warning. Users whose email address differs between Keycloak and Odoo can end up with duplicate accounts or lose access to existing records. Group or role mappings drift when someone edits roles in one system and forgets the other. Network paths also matter, because the Odoo server must reach the token and JWKS endpoints, and clock differences can make token validation fail. Document these checks in the runbook, and include them in the test plan for each upgrade and certificate renewal.
How DeployOpen scopes and delivers Odoo Keycloak SSO
DeployOpen delivers Odoo and Keycloak SSO as a fixed-scope engagement, with the realm, client and user matching decisions agreed in writing before any configuration changes on your Odoo server. The work runs in infrastructure you control, and the handover includes documentation and test evidence your team can reuse. Ongoing support, upgrades and continuous testing are available as a retainer.
How we scope
- The written scope names the Odoo version, Keycloak version and hosting environment in use
- Realm, client and redirect URI decisions are recorded before any configuration begins
- Confirm your Odoo edition and hosting type first, because Odoo plans differ in the hosting they allow
How we build
- Configure the OpenID Connect client in the Keycloak realm for the authorization code flow
- Install and configure the OCA auth_oidc module, then verify token and JWKS endpoint access from Odoo
- Define user matching rules and test how existing Odoo accounts link to Keycloak identities
How we hand over
- Deliver documented client settings, endpoint values and user matching rules for your administrators
- Provide a test plan with recorded results for sign-in, sign-out and rejected login attempts
- Document whether OIDC through auth_oidc or SAML through auth_saml fits your needs, and why
How we support
- Test Odoo and Keycloak upgrades in a copy of the environment before changing production
- Plan for Keycloak's four minor releases a year, tracking Odoo support windows alongside them
- Ongoing support, upgrades and continuous testing are available as a retainer after handover

