Skip to content

Commit 1191dbf

Browse files
committed
[ADD] auth_oauth_code_flow: OAuth2 Authorization Code flow support
This module extends Odoo's auth_oauth to fully support the OAuth2 Authorization Code flow (access_token_code flow), enabling secure authentication with providers like GitHub. Features: - Implements the full OAuth2 Authorization Code handshake (token exchange via POST, user info retrieval via GET). - Supports providers without an id_token (e.g., GitHub) by falling back to Odoo core user creation and validation. - Adds robust handling for cases where the provider does not expose an email: the user's login/username is used as the Odoo login to allow signup and login. - Provider-agnostic: can be used for any OAuth2 provider using code flow, not limited to GitHub. - Includes comprehensive unit tests that mock token exchange and user info retrieval to ensure reliable authentication flows. This module enables Odoo instances to securely authenticate users through modern OAuth2 providers while preserving standard Odoo user management flows.
1 parent 2eb4fed commit 1191dbf

15 files changed

Lines changed: 976 additions & 0 deletions

auth_oauth_code_flow/README.rst

Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
===============================
2+
Authentication OAuth2 Code Flow
3+
===============================
4+
5+
..
6+
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
7+
!! This file is generated by oca-gen-addon-readme !!
8+
!! changes will be overwritten. !!
9+
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
10+
!! source digest: sha256:0c077780615f5637f5a0ca6fffd40821033f390b2d1b6969eabbdb1550546e4e
11+
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
12+
13+
.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png
14+
:target: https://odoo-community.org/page/development-status
15+
:alt: Beta
16+
.. |badge2| image:: https://img.shields.io/badge/licence-AGPL--3-blue.png
17+
:target: http://www.gnu.org/licenses/agpl-3.0-standalone.html
18+
:alt: License: AGPL-3
19+
.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fserver--auth-lightgray.png?logo=github
20+
:target: https://github.com/OCA/server-auth/tree/18.0/auth_oauth_code_flow
21+
:alt: OCA/server-auth
22+
.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png
23+
:target: https://translation.odoo-community.org/projects/server-auth-18-0/server-auth-18-0-auth_oauth_code_flow
24+
:alt: Translate me on Weblate
25+
.. |badge5| image:: https://img.shields.io/badge/runboat-Try%20me-875A7B.png
26+
:target: https://runboat.odoo-community.org/builds?repo=OCA/server-auth&target_branch=18.0
27+
:alt: Try me on Runboat
28+
29+
|badge1| |badge2| |badge3| |badge4| |badge5|
30+
31+
This module provides a high-security implementation of the OAuth2
32+
Authorization Code Flow for Odoo 18. It serves as the essential bridge
33+
for modern identity providers (like GitHub) that have deprecated the
34+
insecure Implicit Flow.
35+
36+
The Security Problem: Why Implicit Flow is Risky
37+
------------------------------------------------
38+
39+
Standard Odoo and many older modules rely on the OAuth2 Implicit Flow.
40+
In this flow, the access_token is sent directly to the user's browser in
41+
the URL fragment
42+
43+
- Leakage: Tokens are visible in browser history, server logs, and can
44+
be intercepted by malicious browser extensions.
45+
46+
- Exposure: Sensitive credentials "touch" the client side, increasing
47+
the attack surface.
48+
49+
Authorization Code Flow
50+
-----------------------
51+
52+
This module implements the Authorization Code Flow (access_token_code),
53+
which is the industry standard for secure web applications.
54+
55+
- Server-to-Server: The access_token is exchanged in a secure backend
56+
POST request between Odoo and the Provider.
57+
58+
- Invisible Tokens: Sensitive tokens never appear in the browser URL or
59+
history.
60+
61+
- PKCE Ready: Supports Proof Key for Code Exchange (PKCE) to prevent
62+
authorization code injection attacks.
63+
64+
Key Value for Developers
65+
66+
- Hybrid Support: Works in harmony with the OCA auth_oidc module. It
67+
acts as a pre-processor for the token handshake, allowing strict OIDC
68+
providers (Keycloak/Cognito) and standard OAuth2 providers (GitHub) to
69+
coexist on the same login page.
70+
71+
**Table of contents**
72+
73+
.. contents::
74+
:local:
75+
76+
Configuration
77+
=============
78+
79+
Automatic System Parameters
80+
---------------------------
81+
82+
Upon installation, this module automatically configures the following
83+
system parameter:
84+
85+
- auth_oauth.authorization_header: Set to 1.
86+
87+
Purpose: This forces Odoo to send the access_token in the HTTP
88+
Authorization Header (Bearer ) rather than as a query parameter in the
89+
URL. GitHub and most modern providers have deprecated URL-based tokens
90+
for security reasons.
91+
92+
Bug Tracker
93+
===========
94+
95+
Bugs are tracked on `GitHub Issues <https://github.com/OCA/server-auth/issues>`_.
96+
In case of trouble, please check there if your issue has already been reported.
97+
If you spotted it first, help us to smash it by providing a detailed and welcomed
98+
`feedback <https://github.com/OCA/server-auth/issues/new?body=module:%20auth_oauth_code_flow%0Aversion:%2018.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_.
99+
100+
Do not contact contributors directly about support or help with technical issues.
101+
102+
Credits
103+
=======
104+
105+
Authors
106+
-------
107+
108+
* KOBROS-TECH LTD
109+
110+
Contributors
111+
------------
112+
113+
- Mohamed Alkobrosli <mohamed@kobros-tech.com>
114+
115+
Maintainers
116+
-----------
117+
118+
This module is maintained by the OCA.
119+
120+
.. image:: https://odoo-community.org/logo.png
121+
:alt: Odoo Community Association
122+
:target: https://odoo-community.org
123+
124+
OCA, or the Odoo Community Association, is a nonprofit organization whose
125+
mission is to support the collaborative development of Odoo features and
126+
promote its widespread use.
127+
128+
.. |maintainer-kobros-tech| image:: https://github.com/kobros-tech.png?size=40px
129+
:target: https://github.com/kobros-tech
130+
:alt: kobros-tech
131+
132+
Current `maintainer <https://odoo-community.org/page/maintainer-role>`__:
133+
134+
|maintainer-kobros-tech|
135+
136+
This module is part of the `OCA/server-auth <https://github.com/OCA/server-auth/tree/18.0/auth_oauth_code_flow>`_ project on GitHub.
137+
138+
You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

auth_oauth_code_flow/__init__.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# Copyright 2026 KOBROS-TECH LTD <https://www.kobros-tech.com>
2+
# License: AGPL-3.0 or later (http://www.gnu.org/licenses/agpl)
3+
4+
from . import models
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# Copyright 2026 KOBROS-TECH LTD <https://www.kobros-tech.com>
2+
# License: AGPL-3.0 or later (http://www.gnu.org/licenses/agpl)
3+
4+
{
5+
"name": "Authentication OAuth2 Code Flow",
6+
"version": "18.0.1.0.0",
7+
"license": "AGPL-3",
8+
"author": ("KOBROS-TECH LTD, " "Odoo Community Association (OCA)"),
9+
"maintainers": ["kobros-tech"],
10+
"website": "https://github.com/OCA/server-auth",
11+
"summary": """
12+
Adds Authorization Code Flow support to OAuth2 (e.g., GitHub)
13+
""",
14+
"depends": ["auth_oauth", "auth_oidc"],
15+
"data": [
16+
"data/auth_oauth_data.xml",
17+
],
18+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<?xml version="1.0" encoding="utf-8" ?>
2+
<odoo noupdate="1">
3+
<!--
4+
Force Odoo to use the 'Authorization: Bearer' header
5+
instead of the URL query parameter for UserInfo validation.
6+
This is a strict requirement for GitHub and modern OAuth2 providers.
7+
-->
8+
<record id="auth_oauth_authorization_header" model="ir.config_parameter">
9+
<field name="key">auth_oauth.authorization_header</field>
10+
<field name="value">1</field>
11+
</record>
12+
</odoo>
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# Copyright 2026 KOBROS-TECH LTD <https://www.kobros-tech.com>
2+
# License: AGPL-3.0 or later (http://www.gnu.org/licenses/agpl)
3+
4+
from . import auth_oauth_provider
5+
from . import res_users
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# Copyright 2026 KOBROS-TECH LTD <https://www.kobros-tech.com>
2+
# License: AGPL-3.0 or later (http://www.gnu.org)
3+
4+
from odoo import fields, models
5+
6+
7+
class AuthOauthProvider(models.Model):
8+
_inherit = "auth.oauth.provider"
9+
10+
flow = fields.Selection(
11+
selection_add=[
12+
("access_token_code", "OAuth2 (Authorization Code Flow)"),
13+
],
14+
ondelete={"access_token_code": "set default"},
15+
string="Auth Flow",
16+
required=True,
17+
default="access_token",
18+
)
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
# Copyright 2026 KOBROS-TECH LTD <https://www.kobros-tech.com>
2+
# License: AGPL-3.0 or later (http://www.gnu.org)
3+
4+
import logging
5+
6+
from odoo import api, models
7+
from odoo.exceptions import AccessDenied
8+
9+
_logger = logging.getLogger(__name__)
10+
11+
12+
class ResUsers(models.Model):
13+
_inherit = "res.users"
14+
15+
@api.model
16+
def auth_oauth(self, provider, params):
17+
oauth_provider = self.env["auth.oauth.provider"].browse(provider)
18+
# 1. Handle specific flow (OAuth2 Code Flow)
19+
if oauth_provider.flow == "access_token_code":
20+
# Perform the handshake (POST exchange)
21+
access_token, id_token = self._auth_oauth_get_tokens_auth_code_flow(
22+
oauth_provider, params
23+
)
24+
if not access_token:
25+
_logger.error("No access_token in response.")
26+
raise AccessDenied()
27+
# 2. THE KEY:
28+
# If it's GitHub (no id_token), bypass OIDC and use Odoo core
29+
if not id_token:
30+
params["access_token"] = access_token
31+
# By returning super()
32+
# we let base Odoo handle UserInfo validation
33+
return super().auth_oauth(provider, params)
34+
# 3. For everything else (OpenID)
35+
# let the chain continue
36+
return super().auth_oauth(provider, params)
37+
38+
@api.model
39+
def _auth_oauth_validate(self, provider, access_token):
40+
validation = super()._auth_oauth_validate(provider, access_token)
41+
# If Odoo couldn't find an email, use the login/username
42+
if not validation.get("email") and validation.get("login"):
43+
validation["email"] = validation["login"]
44+
return validation
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
[build-system]
2+
requires = ["whool"]
3+
build-backend = "whool.buildapi"
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
## Automatic System Parameters
2+
3+
Upon installation, this module automatically configures the following system parameter:
4+
5+
- auth_oauth.authorization_header: Set to 1.
6+
7+
Purpose: This forces Odoo to send the access_token in the HTTP Authorization Header (Bearer <token>) rather than as a query parameter in the URL.
8+
GitHub and most modern providers have deprecated URL-based tokens for security reasons.
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
- Mohamed Alkobrosli \<<mohamed@kobros-tech.com>\>

0 commit comments

Comments
 (0)