-
-
Notifications
You must be signed in to change notification settings - Fork 378
[17.0][ADD] fastapi_auth_apikey #544
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Closed
Closed
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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"], | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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: | ||
| 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 | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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", | ||
| ) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,3 @@ | ||
| [build-system] | ||
| requires = ["whool"] | ||
| build-backend = "whool.buildapi" |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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). |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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. |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
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_idon 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.There was a problem hiding this comment.
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
There was a problem hiding this comment.
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?