Hi everyone!
In my case, with Odoo 18 with Nginx and despite having the web.base.url set to HTTPS, the Google OAuth authentication wasn't working. After analyzing and updating the code to make it more flexible, I've created a fixed version of the auth_oauth module that solves the common issues.
🔧 Issues Resolved:
🔒 HTTP URLs being sent to Google OAuth2
👤 Authentication failure with existing users
🌐 Google's redirect_uri_mismatch error
✉️ Duplicate email handling
💻 Code Improvements and changes made:
In controllers/main.py - list_providers method:
Added logic to force HTTPS on redirect URL Prevents Google rejection for HTTP use Maintains compatibility with existing configurations
- Changes made in file main.py
def list_providers(self):
try:
providers = request.env['auth.oauth.provider'].sudo().search_read([('enabled', '=', True)])
except Exception:
providers = []
for provider in providers:
# Force HTTPS in redirect URL
base_url = request.httprequest.url_root
if base_url.startswith('http://'):
base_url = base_url.replace('http://', 'https://', 1)
return_url = base_url + 'auth_oauth/signin'
state = self.get_state(provider)
params = dict(
response_type='token',
client_id=provider['client_id'],
redirect_uri=return_url,
scope=provider['scope'],
state=json.dumps(state),
# nonce=base64.urlsafe_b64encode(os.urandom(16)),
)
provider['auth_link'] = "%s?%s" % (provider['auth_endpoint'], werkzeug.urls.url_encode(params))
return providers
- Changes made in /models/res_users.py
_auth_oauth_validate method:
Added detailed logging of the validation process Better error handling and response validation Clearer information about the authentication process
_auth_oauth_signin method:
User search by email was implemented in addition to oauth_uid Automatic management of existing users Updating OAuth credentials for existing users Improved logging for diagnostics
@api.model def _auth_oauth_validate(self, provider, access_token):
""" return the validation data corresponding to the access token """
oauth_provider = self.env['auth.oauth.provider'].browse(provider)
validation = self._auth_oauth_rpc(oauth_provider.validation_endpoint, access_token)
if validation.get("error"):
_logger.error("OAuth validation error: %s", validation['error'])
raise Exception(validation['error'])
if oauth_provider.data_endpoint:
data = self._auth_oauth_rpc(oauth_provider.data_endpoint, access_token)
validation.update(data)
# Logging the validation data
subject = next(filter(None, [
validation.pop(key, None)
for key in [
'sub', # standard
'id', # google v1 userinfo, facebook opengraph
'user_id', # google tokeninfo, odoo (tokeninfo)
]
]), None)
if not subject:
_logger.error("Missing subject identity in validation data")
raise AccessDenied('Missing subject identity')
validation['user_id'] = subject
return validation
@api.model
def _auth_oauth_signin(self, provider, validation, params):
""" retrieve and sign in the user corresponding to provider and validated access token
:param provider: oauth provider id (int)
:param validation: result of validation of access token (dict)
:param params: oauth parameters (dict)
:return: user login (str)
:raise: AccessDenied if signin failed
This method can be overridden to add alternative signin methods.
"""
oauth_uid = validation['user_id']
email = validation.get('email')
try:
# First search for oauth_uid
oauth_user = self.search([("oauth_uid", "=", oauth_uid), ('oauth_provider_id', '=', provider)])
if not oauth_user and email:
# If not found, search by email.
oauth_user = self.search([("login", "=", email)])
if oauth_user:
# If the user with that email exists, we update their OAuth data
oauth_user.write({
'oauth_provider_id': provider,
'oauth_uid': oauth_uid,
'oauth_access_token': params['access_token']
})
if not oauth_user:
raise AccessDenied()
assert len(oauth_user) == 1
oauth_user.write({'oauth_access_token': params['access_token']})
return oauth_user.login
except AccessDenied as access_denied_exception:
if self.env.context.get('no_user_creation'):
return None
state = json.loads(params['state'])
token = state.get('t')
values = self._generate_signup_values(provider, validation, params)
try:
login, _ = self.signup(values, token)
return login
except (SignupError, UserError) as e:
_logger.error("Failed to create new user: %s", str(e))
raise access_denied_exception
You can find it on github:
(Sorry but I can't post links yet.)
diegonaranjo/odoo-addons-auth_oauth
Please make sure to backup your existing module before making any changes. If you encounter any issues or need help, feel free to open an issue on the GitHub repository.
Hope this helps!
i am also facing same issue any solution please