Skip to content

Odoo18 Create API Login

  • Odoo
odoo18 create api login

Successfully implementing an odoo18 create api login mechanism is paramount for any developer looking to build secure and robust integrations with Odoo 18. A critical component of this process is the generation and management of access tokens. Consequently, this tutorial will delve deep into why access tokens are essential and provide a step-by-step guide on how to create and manage them within your Odoo 18 environment. Furthermore, by understanding this, you can ensure that external applications interact with your Odoo instance securely and efficiently, making the odoo18 create api login flow complete.

The Ultimate Guide to Secure Access Tokens

source code : https://gitlab.com/hazem.abdalazeem/project_api

The Indispensable Role of Access Tokens in Odoo API Security

When an external application, such as a mobile app or a third-party web service, needs to interact with your Odoo 18 data, it first needs to authenticate itself. However, sending raw usernames and passwords with every single API request is a significant security risk. If a malicious actor intercepts these credentials, they could gain unauthorized access to your system. This is precisely where access tokens come into play as a more secure alternative for your odoo18 create api login strategy.

What is an API Access Token?

An API access token is essentially a string of characters that an application uses to make authenticated requests to an API after an initial login. Think of it as a temporary digital key. Initially, the user provides their credentials (username and password) once during the login process. If these credentials are valid, Odoo then generates a unique access token and sends it back to the client application. Subsequently, for all future requests, the client application includes this access token (usually in the request header) instead of the original credentials. Odoo can then validate this token to authorize the request.

Why Prioritize Access Tokens for Your Odoo 18 API Login?

Using access tokens offers several compelling advantages for your odoo18 create api login system:

  1. Enhanced Security: It significantly reduces the exposure of actual user credentials. Since the token is sent with subsequent requests, the username and password are not repeatedly transmitted over the network.
  2. Limited Lifespan: Access tokens can, and should, be configured to expire after a certain period. This limits the time window during which a compromised token can be misused.
  3. Granular Permissions (Scope): Tokens can be associated with specific permissions or scopes, restricting what an application can do on behalf of the user.
  4. Revocation: Individual tokens can be revoked if they are suspected of being compromised, without affecting the user’s primary credentials.

The core idea is simple: authenticate once with credentials, then use a temporary, securer token for ongoing communication.

Building the Foundation: The Access Token Model in Odoo 18

To manage access tokens effectively, you first need a place to store them within Odoo. This typically involves creating a new model. Let’s define an api.access.token model.

Defining the api.access.token Model Structure

You will create a new Python file in the models directory of your custom Odoo module (e.g., api_access_token.py). This model will store the token itself, link it to a user, define its expiration, and potentially its scope.

from odoo import models, fields, api
from datetime import datetime, timedelta
import secrets # For generating cryptographically strong random tokens

class ApiAccessToken(models.Model):
_name = 'api.access.token'
_description = 'API Access Token for Odoo 18 Integrations'

token = fields.Char(string='Access Token', required=True, index=True)
user_id = fields.Many2one('res.users', string='User', required=True, ondelete='cascade')
expiry_date = fields.Datetime(string='Expiry Date', required=True)
scope = fields.Char(string='Scope', help="Optional: Define permissions like 'user_info read_projects'") # Example scope

_sql_constraints = [
    ('token_uniq', 'unique (token)', 'Access token must be unique!')
]

def is_expired(self):
    self.ensure_one()
    return datetime.now() > self.expiry_date

In this model:

  • token: Stores the actual access token string. It’s indexed for faster lookups.
  • user_id: A many-to-one relationship linking the token to an Odoo user (res.users). ondelete='cascade' means if the user is deleted, their tokens are also deleted.
  • expiry_date: A datetime field indicating when the token will no longer be valid.
  • scope: An optional field to define what the token is allowed to do.
  • is_expired(): A helper method to easily check if a token instance has passed its expiry date.

Remember to include this new model file in your module’s __init__.py under models and add appropriate access rights (ACLs) for this model, typically restricting direct write access except for specific service users or through controlled methods.

Crafting the Logic: Generating and Retrieving Access Tokens

With the model in place, the next step is to implement the logic for creating new tokens and finding existing, valid ones. This is often encapsulated in a method within the api.access.token model itself or a helper class. The SRT file refers to a method like findOrCreateToken.

Implementing the find_or_create_token Method

This method will be responsible for:

  1. Checking if a valid, non-expired token already exists for the given user.
  2. If not, creating a new token with a defined expiry period.
  3. Returning the token string.

Let’s add this method to our ApiAccessToken class:

class ApiAccessToken(models.Model):
_name = 'api.access.token'
_description = 'API Access Token for Odoo 18 Integrations'

# ... (fields and is_expired method as defined before) ...

@api.model
def find_or_create_token(self, user_id, create_if_not_found=True):
    """
    Finds an existing, valid token for the user or creates a new one.
    :param user_id: The ID of the res.users.
    :param create_if_not_found: Boolean, if True, creates a token if no valid one is found.
    :return: The access token string or None.
    """
    if not user_id:
        return None

    # Search for an existing, non-expired token for this user
    # Order by expiry_date descending to get the one that expires latest if multiple somehow exist
    domain = [
        ('user_id', '=', user_id),
        ('expiry_date', '>', datetime.now())
    ]
    existing_token = self.search(domain, order='expiry_date desc', limit=1)

    if existing_token:
        # Optional: You might want to update the expiry_date of an existing token (sliding window)
        # For simplicity here, we just return it if valid.
        return existing_token.token

    if not create_if_not_found:
        return None

    # No valid token found, and we are allowed to create one.
    # Define token lifespan (e.g., from system parameters or hardcoded)
    # The SRT mentions getting this from parameters or setting it to 1 day.
    token_lifespan_hours = int(self.env['ir.config_parameter'].sudo().get_param('api.token_lifespan_hours', '24'))

    new_expiry_date = datetime.now() + timedelta(hours=token_lifespan_hours)

    # Generate a cryptographically strong random token
    # The SRT mentions a prefix and random bytes. secrets.token_urlsafe is a good option.
    new_token_string = f"atk_{secrets.token_urlsafe(32)}" # "atk_" for "access token" prefix

    vals = {
        'user_id': user_id,
        'token': new_token_string,
        'expiry_date': new_expiry_date,
        'scope': 'user_info default_scope', # Example default scope
    }

    try:
        new_token_record = self.create(vals)
        self.env.cr.commit() # Commit immediately to ensure token is available
        return new_token_record.token
    except Exception as e:
        # Log the error
        self.env.cr.rollback() # Rollback in case of error during creation
        # Consider raising a specific exception or returning None
        return None

Explanation of find_or_create_token:

  • It first checks if a user_id is provided.
  • Then, it searches for an existing token for that user whose expiry_date is still in the future.
  • If a valid token is found, its string is returned.
  • If no valid token exists and create_if_not_found is True:
    • It determines the token’s lifespan. Here, it tries to get it from an Odoo system parameter api.token_lifespan_hours (defaulting to 24 hours). You’d need to add this system parameter via Odoo’s UI or an XML data file.
    • A new expiry_date is calculated.
    • A secure random token string is generated using secrets.token_urlsafe(). The prefix atk_ is added for easier identification.
    • A new api.access.token record is created with the user ID, the new token string, and its expiry date.
    • The new token string is returned.
  • Error handling is included to rollback the transaction if token creation fails.

Integrating Token Generation into the Odoo18 Create API Login Flow

Now, let’s see how this token generation logic fits into the actual API login endpoint. This assumes you have a basic login endpoint that authenticates a user (as might have been covered in a preceding tutorial or the first part of an API series). After successful authentication using request.session.authenticate(db, login, password), you would call your find_or_create_token method.

Modifying Your Login Controller

Let’s assume you have a controller similar to this for handling the initial login:

from odoo import http
from odoo.http import request, Response
from odoo.exceptions import AccessDenied, AccessError
import json

class ApiAuthController(http.Controller):

@http.route('/api/auth/login', type='http', auth='none', methods=['POST'], csrf=False)
def api_login(self, **kwargs):
    # Extract db, login, password from request headers or body
    # For example, from headers as shown in the SRT context:
    db_name = request.httprequest.headers.get('db')
    login = request.httprequest.headers.get('login')
    password = request.httprequest.headers.get('password')

    if not all([db_name, login, password]):
        # Return 400 Bad Request if credentials are missing
        response_data = {"success": False, "error": "missing_credentials", "message": "Database, login, and password are required."}
        return Response(json.dumps(response_data), content_type='application/json', status=400)

    try:
        # Authenticate the user
        uid = request.session.authenticate(db_name, login, password)
        if not uid: # Should be caught by AccessDenied, but as a safeguard
            raise AccessDenied("Authentication failed, UID not returned.")

        # User authenticated successfully, now get/create an access token
        AccessToken = request.env['api.access.token'].sudo() # Use sudo if ACLs are restrictive
        access_token_str = AccessToken.find_or_create_token(user_id=uid)

        if not access_token_str:
            response_data = {"success": False, "error": "token_generation_failed", "message": "Could not generate access token."}
            return Response(json.dumps(response_data), content_type='application/json', status=500)

        # Prepare successful response
        user = request.env['res.users'].browse(uid)
        response_data = {
            "success": True,
            "uid": uid,
            "name": user.name,
            "username": user.login,
            "email": user.email,
            "company_id": user.company_id.id if user.company_id else None,
            "company_name": user.company_id.name if user.company_id else None,
            "access_token": access_token_str,
            "token_type": "Bearer",
            # You can fetch the actual expiry from the token record if needed
            # "expires_in": token_lifespan_hours * 3600 # Example
        }
        return Response(json.dumps(response_data), content_type='application/json', status=200)

    except AccessDenied:
        response_data = {"success": False, "error": "access_denied", "message": "Invalid login or password."}
        return Response(json.dumps(response_data), content_type='application/json', status=401)
    except AccessError: # More general access issue
        response_data = {"success": False, "error": "access_error", "message": "A general access error occurred."}
        return Response(json.dumps(response_data), content_type='application/json', status=403)
    except Exception as e:
        # Log the exception e
        response_data = {"success": False, "error": "internal_server_error", "message": f"An unexpected error occurred: {str(e)}"}
        return Response(json.dumps(response_data), content_type='application/json', status=500)

Key changes in the login controller:

  1. After request.session.authenticate successfully returns a uid, we get a reference to our api.access.token model.
  2. We call find_or_create_token(user_id=uid) to get an access token string.
  3. If token generation fails, an appropriate error is returned.
  4. The successful JSON response now includes the access_token and token_type (commonly “Bearer”). It also includes other useful user information that the client application might need.

Testing Your Secure Odoo18 API Login

You can test this entire flow using an API client tool like Postman.

  1. Set up a POST request to your /api/auth/login endpoint.
  2. In the Headers tab, add db, login, and password with appropriate values.
  3. Send the request.
  4. If successful, the response body should be a JSON object containing the user’s details and, most importantly, the access_token.

You should also test error cases:

  • Missing credentials.
  • Incorrect credentials (should return 401 Access Denied).
  • Verify that if you log in again (while the previous token is still valid), you might get the same token or a new one depending on your find_or_create_token logic (our current logic returns the existing valid one).
  • Verify token expiration by waiting for the token to expire and then trying to use it (this would be tested in subsequent API calls that use the token).

Utilizing the Access Token in Subsequent API Calls

Once the client application receives the access token, it must include this token in the Authorization header for all subsequent requests to protected Odoo API endpoints. The standard format is:

Authorization: Bearer <your_access_token_string>

Your other API endpoints (for reading/writing data) will then need to:

  1. Extract this token from the header.
  2. Validate it against your api.access.token model (check if it exists and is not expired).
  3. If valid, identify the associated user and process the request in their context.

Final Thoughts and Best Practices for Odoo18 Create API Login

Implementing a secure odoo18 create api login flow with access tokens is a crucial step in building reliable Odoo integrations.

  • Always use HTTPS to protect tokens (and credentials) in transit.
  • Keep token lifespans reasonably short. Balance security with user experience. For very sensitive operations, consider even shorter lifespans.
  • Implement a token refresh mechanism if longer user sessions are required without frequent re-logins. This typically involves a separate “refresh token” that is longer-lived and can be used to obtain a new access token.
  • Securely store tokens on the client-side. Use platform-specific secure storage mechanisms.
  • Provide a way to revoke tokens (e.g., a “log out from all devices” feature that invalidates all of a user’s tokens).

By following these guidelines and the steps outlined in this tutorial, you can significantly enhance the security and professionalism of your Odoo 18 API integrations. This robust odoo18 create api login system will serve as a solid foundation for all your external application communications.


Discover more from teguhteja.id

Subscribe to get the latest posts sent to your email.

Leave a Reply

WP Twitter Auto Publish Powered By : XYZScripts.com