Skip to content
Closed
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
135 changes: 135 additions & 0 deletions fastapi_auth_apikey/README.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
===================
Fastapi Auth Apikey
===================

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

.. |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%2Frest--framework-lightgray.png?logo=github
:target: https://github.com/OCA/rest-framework/tree/17.0/fastapi_auth_apikey
:alt: OCA/rest-framework
.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png
:target: https://translation.odoo-community.org/projects/rest-framework-17-0/rest-framework-17-0-fastapi_auth_apikey
: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/rest-framework&target_branch=17.0
:alt: Try me on Runboat

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

This module provides ``FastAPI`` ``Depends`` to allow authentication
with `API
Keys <https://www.odoo.com/documentation/master/developer/reference/external_api.html#api-keys>`__.

**Table of contents**

.. contents::
:local:

Usage
=====

FastAPI API Key Dependencies
----------------------------

The following FastAPI dependencies are provided and importable from
``odoo.addons.fastapi_auth_apikey.dependencies``:

``def apikey_authenticated_partner_impl() -> Partner``
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Return the authenticated partner based on the provided API key. Raise a
401 (unauthorized) if the API key is invalid or the partner could not be
found. Also validates that the user associated with the API key matches
the endpoint’s expected user, if specified.

``def apikey_optionally_authenticated_partner_impl() -> Partner | None``
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Return the authenticated partner based on the provided API key, or an
empty recordset if the key is valid but doesn't match the expected user.
Returns ``None`` if authentication fails silently.

``def apikey_authenticated_partner_env() -> Environment``
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Return an Odoo environment bound to the authenticated partner. The
partner must be authenticated using
``apikey_authenticated_partner_impl``. Raise a 401 if authentication
fails.

``def apikey_authenticated_partner() -> Partner``
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Return the authenticated partner bound to the correct Odoo environment.
This function uses the partner returned by
``apikey_authenticated_partner_impl`` and binds it to the environment
returned by ``apikey_authenticated_partner_env``.

``def apikey_optionally_authenticated_partner_env() -> Environment``
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Return an Odoo environment bound to the optionally authenticated
partner, or a default environment if the partner could not be
authenticated.

``def optionally_authenticated_partner() -> Partner | None``
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Return the optionally authenticated partner bound to the appropriate
environment, or ``None`` if no valid API key was provided.

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

Bugs are tracked on `GitHub Issues <https://github.com/OCA/rest-framework/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/rest-framework/issues/new?body=module:%20fastapi_auth_apikey%0Aversion:%2017.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
-------

* Sygel

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

- `Sygel <https://www.sygel.es>`__:

- Alberto Martínez
- Valentin Vinagre
- Harald Panten

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/rest-framework <https://github.com/OCA/rest-framework/tree/17.0/fastapi_auth_apikey>`_ project on GitHub.

You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.
3 changes: 3 additions & 0 deletions fastapi_auth_apikey/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).

from . import models
16 changes: 16 additions & 0 deletions fastapi_auth_apikey/__manifest__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# Copyright 2025 Alberto Martínez <alberto.martinez@sygel.es>
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
{
"name": "Fastapi Auth Apikey",
"summary": "Auhentication for FastApi using Odoo's built in apikeys",
"version": "17.0.1.0.0",
"website": "https://github.com/OCA/rest-framework",
"author": "Sygel, Odoo Community Association (OCA)",
"license": "AGPL-3",
"application": False,
"installable": True,
"depends": [
"fastapi",
],
"data": ["views/fastapi_endpoint.xml"],
}
98 changes: 98 additions & 0 deletions fastapi_auth_apikey/dependencies.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
# Copyright 2025 Alberto Martínez <alberto.martinez@sygel.es>
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).

from typing import Annotated

from odoo.api import Environment

from odoo.addons.base.models.res_partner import Partner
from odoo.addons.fastapi.dependencies import fastapi_endpoint, odoo_env
from odoo.addons.fastapi.models.fastapi_endpoint import FastapiEndpoint

from fastapi import Depends, HTTPException, status
from fastapi.security import APIKeyHeader


def apikey_authenticated_partner_impl(
api_key: Annotated[
str,
Depends(
APIKeyHeader(
name="api-key",
description="Odoo default apikey",
)
),
],
env: Annotated[Environment, Depends(odoo_env)],
endpoint: Annotated[FastapiEndpoint, Depends(fastapi_endpoint)],
) -> Partner:
uid = env["res.users.apikeys"]._check_credentials(
scope=endpoint.apikey_auth_scope, key=api_key
)
partner = env["res.users"].sudo().browse(uid).exists().partner_id
if not partner:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED, detail="Incorrect API Key"
)
if endpoint.user_id.id and endpoint.user_id.id != uid:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Tisho99 You link your endpoint to only one user? The user_id on the endpoint is the technical user running the process. The authentication is a way to authenticate a partner requesting the endpoint. I'm may be wrong when reading your code but this line will restrict the use of this endpoint to the partner linked to the user_id defined on the endpoint.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @lmignon, sorry for the late response

Yes, my code works that way. Do you see any issue with that approach?

Since API keys in Odoo can be generated by any internal user, this effectively means that, without additional restrictions, any internal user could potentially gain access to the endpoint.

I’ll be thinking about a better approach

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@lmignon How do you see this approach? Do you think it would be better to use a checkbox to indicate which users are allowed?

raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED, detail="Incorrect User"
)
return partner


def apikey_optionally_authenticated_partner_impl(
api_key: Annotated[
str,
Depends(
APIKeyHeader(
name="api-key",
description="Odoo default apikey",
)
),
],
env: Annotated[Environment, Depends(odoo_env)],
endpoint: Annotated[FastapiEndpoint, Depends(fastapi_endpoint)],
) -> Partner | None:
uid = env["res.users.apikeys"]._check_credentials(scope="fastapi", key=api_key)
partner = env["res.users"].sudo().browse(uid).exists().partner_id
if endpoint.user_id.id and endpoint.user_id.id != uid:
partner = env["res.partner"]
return partner


def apikey_authenticated_partner_env(
partner: Annotated[Partner, Depends(apikey_authenticated_partner_impl)]
) -> Environment:
return partner.with_context(authenticated_partner_id=partner.id).env


def apikey_authenticated_partner(
partner: Annotated[Partner, Depends(apikey_authenticated_partner_impl)],
partner_env: Annotated[Environment, Depends(apikey_authenticated_partner_env)],
) -> Partner:
return partner_env["res.partner"].browse(partner.id)


def apikey_optionally_authenticated_partner_env(
partner: Annotated[
Partner | None, Depends(apikey_optionally_authenticated_partner_impl)
],
env: Annotated[Environment, Depends(odoo_env)],
) -> Environment:
if partner:
return partner.with_context(authenticated_partner_id=partner.id).env
return env


def optionally_authenticated_partner(
partner: Annotated[
Partner | None, Depends(apikey_optionally_authenticated_partner_impl)
],
partner_env: Annotated[
Environment, Depends(apikey_optionally_authenticated_partner_env)
],
) -> Partner | None:
if partner:
return partner_env["res.partner"].browse(partner.id)
return None
3 changes: 3 additions & 0 deletions fastapi_auth_apikey/models/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).

from . import fastapi_endpoint
14 changes: 14 additions & 0 deletions fastapi_auth_apikey/models/fastapi_endpoint.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# Copyright 2025 Alberto Martínez <alberto.martinez@sygel.es>
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).

from odoo import fields, models


class FastapiEndpoint(models.Model):
_inherit = "fastapi.endpoint"

apikey_auth_scope = fields.Char(
default="fastapi",
help="If using ApiKey auth in the APP endpoints, "
"the keys with other scopes won't be accepted",
)
3 changes: 3 additions & 0 deletions fastapi_auth_apikey/pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[build-system]
requires = ["whool"]
build-backend = "whool.buildapi"
4 changes: 4 additions & 0 deletions fastapi_auth_apikey/readme/CONTRIBUTORS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
- [Sygel](https://www.sygel.es):
- Alberto Martínez
- Valentin Vinagre
- Harald Panten
3 changes: 3 additions & 0 deletions fastapi_auth_apikey/readme/DESCRIPTION.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
This module provides `FastAPI` `Depends` to allow authentication with
[API
Keys](https://www.odoo.com/documentation/master/developer/reference/external_api.html#api-keys).
41 changes: 41 additions & 0 deletions fastapi_auth_apikey/readme/USAGE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
## FastAPI API Key Dependencies

The following FastAPI dependencies are provided and importable from
`odoo.addons.fastapi_auth_apikey.dependencies`:

### `def apikey_authenticated_partner_impl() -> Partner`

Return the authenticated partner based on the provided API key. Raise a
401 (unauthorized) if the API key is invalid or the partner could not be
found. Also validates that the user associated with the API key matches
the endpoint’s expected user, if specified.

### `def apikey_optionally_authenticated_partner_impl() -> Partner | None`

Return the authenticated partner based on the provided API key, or an
empty recordset if the key is valid but doesn't match the expected user.
Returns `None` if authentication fails silently.

### `def apikey_authenticated_partner_env() -> Environment`

Return an Odoo environment bound to the authenticated partner. The
partner must be authenticated using `apikey_authenticated_partner_impl`.
Raise a 401 if authentication fails.

### `def apikey_authenticated_partner() -> Partner`

Return the authenticated partner bound to the correct Odoo environment.
This function uses the partner returned by
`apikey_authenticated_partner_impl` and binds it to the environment
returned by `apikey_authenticated_partner_env`.

### `def apikey_optionally_authenticated_partner_env() -> Environment`

Return an Odoo environment bound to the optionally authenticated
partner, or a default environment if the partner could not be
authenticated.

### `def optionally_authenticated_partner() -> Partner | None`

Return the optionally authenticated partner bound to the appropriate
environment, or `None` if no valid API key was provided.
Binary file added fastapi_auth_apikey/static/description/icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading