Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
107 changes: 107 additions & 0 deletions auth_session_scheduled_logout/README.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
========================
Scheduled Session Logout
========================

..
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! source digest: sha256:e95d136b9f41fab8af17e33dc5863aa6ee89f13c45cc001d4617cbbc86c88359
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png
:target: https://odoo-community.org/page/development-status
:alt: Beta
.. |badge2| image:: https://img.shields.io/badge/licence-AGPL--3-blue.png
:target: http://www.gnu.org/licenses/agpl-3.0-standalone.html
:alt: License: AGPL-3
.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fserver--auth-lightgray.png?logo=github
:target: https://github.com/OCA/server-auth/tree/18.0/auth_session_scheduled_logout
:alt: OCA/server-auth
.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png
:target: https://translation.odoo-community.org/projects/server-auth-18-0/server-auth-18-0-auth_session_scheduled_logout
:alt: Translate me on Weblate
.. |badge5| image:: https://img.shields.io/badge/runboat-Try%20me-875A7B.png
:target: https://runboat.odoo-community.org/builds?repo=OCA/server-auth&target_branch=18.0
:alt: Try me on Runboat

|badge1| |badge2| |badge3| |badge4| |badge5|

This module forces logout of all active user sessions on a schedule
(defaults to every Sunday at 23:00), regardless of user activity. It's
not an inactivity timeout: even users actively working are logged out at
scheduled time. At the scheduled time every targeted browser session
becomes invalid. On next request the user is redirected to the login
page.

Installing or upgrading the module logs nobody out: the timestamp is
empty for existing users, and leaves the token untouched while it is
empty, so current sessions keep working until the scheduled job runs.
Users can be excluded from the logout by adding them to the security
group *Exempt from Scheduled Session Logout*.

**Table of contents**

.. contents::
:local:

Configuration
=============

**Schedule**

Go to *Settings > Technical > Automation > Scheduled Actions* and open
*Scheduled Session Logout: revoke all sessions*.

- By default it runs **every Sunday at 23:00 UTC**.
- Adjust *Next Execution Date* and the interval to fit your needs.
- Deactivate the scheduled action to disable the feature entirely.

**Excluding users**

To keep some users logged in when the job runs, add them to the security
group *Exempt from Scheduled Session Logout*. The group appears as a
checkbox in the *Other* section of the user form (*Settings > Users*).

Bug Tracker
===========

Bugs are tracked on `GitHub Issues <https://github.com/OCA/server-auth/issues>`_.
In case of trouble, please check there if your issue has already been reported.
If you spotted it first, help us to smash it by providing a detailed and welcomed
`feedback <https://github.com/OCA/server-auth/issues/new?body=module:%20auth_session_scheduled_logout%0Aversion:%2018.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_.

Do not contact contributors directly about support or help with technical issues.

Credits
=======

Authors
-------

* ForgeFlow

Contributors
------------

- ForgeFlow S.L. <contact@forgeflow.com>

- Laura Cazorla <laura.cazorla@forgeflow.com>

Maintainers
-----------

This module is maintained by the OCA.

.. image:: https://odoo-community.org/logo.png
:alt: Odoo Community Association
:target: https://odoo-community.org

OCA, or the Odoo Community Association, is a nonprofit organization whose
mission is to support the collaborative development of Odoo features and
promote its widespread use.

This module is part of the `OCA/server-auth <https://github.com/OCA/server-auth/tree/18.0/auth_session_scheduled_logout>`_ project on GitHub.

You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.
2 changes: 2 additions & 0 deletions auth_session_scheduled_logout/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
from . import models
from .hooks import post_init_hook
19 changes: 19 additions & 0 deletions auth_session_scheduled_logout/__manifest__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Copyright 2026 ForgeFlow S.L.
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).

{
"name": "Scheduled Session Logout",
"summary": "Force logout of all active user sessions on a schedule",
"version": "18.0.1.0.0",
"category": "Tools",
"author": "ForgeFlow, Odoo Community Association (OCA)",
"website": "https://github.com/OCA/server-auth",
"license": "AGPL-3",
"depends": ["base"],
"data": [
"security/auth_session_scheduled_logout_groups.xml",
"data/ir_cron_data.xml",
],
"post_init_hook": "post_init_hook",
"installable": True,
}
16 changes: 16 additions & 0 deletions auth_session_scheduled_logout/data/ir_cron_data.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="utf-8" ?>
<!-- Copyright 2026 ForgeFlow S.L.
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). -->
<odoo noupdate="1">
<record id="cron_revoke_all_sessions" model="ir.cron">
<field name="name">Scheduled Session Logout: revoke all sessions</field>
<field name="model_id" ref="base.model_res_users" />
<field name="state">code</field>
<field name="code">model._cron_revoke_all_sessions()</field>
<field name="interval_number">1</field>
<field name="interval_type">weeks</field>
<field name="nextcall">2099-01-04 23:00:00</field>
<field name="active" eval="True" />
<field name="user_id" ref="base.user_root" />
</record>
</odoo>
23 changes: 23 additions & 0 deletions auth_session_scheduled_logout/hooks.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Copyright 2026 ForgeFlow S.L.
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).

import logging
from datetime import datetime, time, timedelta

from odoo import fields

_logger = logging.getLogger(__name__)


def post_init_hook(env):
# Schedule the first run at the next Sunday 23:00 (UTC)
cron = env.ref("auth_session_scheduled_logout.cron_revoke_all_sessions")
if not cron:
return
now = fields.Datetime.now()
ahead = (6 - now.weekday()) % 7
next_call = datetime.combine(now.date() + timedelta(days=ahead), time(23, 0))
if next_call <= now:
next_call += timedelta(days=7)
cron.nextcall = next_call
_logger.info("Scheduled first session logout for %s UTC.", next_call)
1 change: 1 addition & 0 deletions auth_session_scheduled_logout/models/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from . import res_users
62 changes: 62 additions & 0 deletions auth_session_scheduled_logout/models/res_users.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
# Copyright 2026 ForgeFlow S.L.
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).

import hmac
import logging
from hashlib import sha256

from odoo import api, fields, models

_logger = logging.getLogger(__name__)


class ResUsers(models.Model):
_inherit = "res.users"

auth_session_valid_from = fields.Datetime(
string="Sessions Valid From",
copy=False,
readonly=True,
help="Any browser session opened before this datetime is invalid: the "
"user is redirected to the login page on their next request. The value "
"is bumped by scheduled logout job and folded into the session token.",
)

def _compute_session_token(self, sid):
token = super()._compute_session_token(sid)
if not token:
return token
valid_from = self.sudo().auth_session_valid_from
if valid_from:
token_encoded = token.encode("utf-8")
valid_from_encoded = valid_from.isoformat().encode("utf-8")
encoded = hmac.new(token_encoded, valid_from_encoded, sha256)
token = encoded.hexdigest()
return token

@api.model
def _get_scheduled_logout_exempt_group(self):
group_id = "auth_session_scheduled_logout.group_auth_session_no_sched_logout"
group = self.env.ref(group_id, raise_if_not_found=False)
return group or self.env["res.groups"]

@api.model
def _get_users_to_logout(self):
domain = []
exempt_group = self._get_scheduled_logout_exempt_group()
if exempt_group:
domain.append(("groups_id", "not in", exempt_group.ids))
users = self.search(domain)
tech_users = self.browse()
for xmlid in ("base.public_user", "base.default_user"):
if self.env.ref(xmlid, raise_if_not_found=False):
tech_users |= self.env.ref(xmlid, raise_if_not_found=False)
return users - tech_users

@api.model
def _cron_revoke_all_sessions(self):
users = self._get_users_to_logout()
if not users:
return
users.write({"auth_session_valid_from": fields.Datetime.now()})
_logger.info("Scheduled logout: revoked sessions for %d user(s).", len(users))
3 changes: 3 additions & 0 deletions auth_session_scheduled_logout/pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[build-system]
requires = ["whool"]
build-backend = "whool.buildapi"
14 changes: 14 additions & 0 deletions auth_session_scheduled_logout/readme/CONFIGURE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
**Schedule**

Go to *Settings > Technical > Automation > Scheduled Actions* and open
*Scheduled Session Logout: revoke all sessions*.

- By default it runs **every Sunday at 23:00 UTC**.
- Adjust *Next Execution Date* and the interval to fit your needs.
- Deactivate the scheduled action to disable the feature entirely.

**Excluding users**

To keep some users logged in when the job runs, add them to the security group
*Exempt from Scheduled Session Logout*. The group appears as a checkbox in the
*Other* section of the user form (*Settings > Users*).
2 changes: 2 additions & 0 deletions auth_session_scheduled_logout/readme/CONTRIBUTORS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
- ForgeFlow S.L. \<<contact@forgeflow.com>\>
- Laura Cazorla \<<laura.cazorla@forgeflow.com>\>
11 changes: 11 additions & 0 deletions auth_session_scheduled_logout/readme/DESCRIPTION.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
This module forces logout of all active user sessions on a schedule (defaults
to every Sunday at 23:00), regardless of user activity. It's not an inactivity
timeout: even users actively working are logged out at scheduled time. At the
scheduled time every targeted browser session becomes invalid. On next request
the user is redirected to the login page.

Installing or upgrading the module logs nobody out: the timestamp is empty for
existing users, and leaves the token untouched while it is empty, so current
sessions keep working until the scheduled job runs. Users can be excluded from
the logout by adding them to the security group *Exempt from Scheduled Session
Logout*.
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8" ?>
<!-- Copyright 2026 ForgeFlow S.L.
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). -->
<odoo>
<record id="group_auth_session_no_sched_logout" model="res.groups">
<field name="name">Exempt from Scheduled Session Logout</field>
<field
name="comment"
>Members of this group keep their sessions when the scheduled logout job runs.</field>
</record>
</odoo>
Loading
Loading