rokdd
rokdd

Reputation: 652

Auth with JWT in web2py

I run with web2py a rest api in the controller and there my jwt and the token works. In the model I am using fields with default values but this fields are never filled automatically because auth.user is None. I tried to init it manually but it does not work.

Sites.py:

if auth.user is None:
    auth = Auth(db, jwt = {'secret_key':'..hnv', 'user_param':"email"})
    #auth.jwt()
    auth.basic()
    #auth.user.update()

I tried also to add the parameter in db.py but no success:

auth = Auth(db,jwt = {'secret_key':'...', 'user_param':"email"}, host_names=configuration.get('host.names'))

Does I expect too much or I am doing something wrong?

Upvotes: 0

Views: 352

Answers (1)

Anthony
Anthony

Reputation: 25536

auth = Auth(db, jwt = {'secret_key':'...', 'user_param':"email"})

If you instatiate Auth as above (i.e., adding the JWT functionality), when a request with a JWT token comes in, auth.user is not immediately populated when the above line is executed. Rather, the token is only read and auth.user populated when the @auth.allows_jwt() decorator is executed (i.e., in the requested controller). This means that in your model files where you have your DAL table definitions, auth.user (and auth.user_id and auth.user_groups) will still be None during requests authorized via JWT, so you cannot directly use those values as field defaults.

As an alternative, you can instead specify a function as a field default, with the function returning the relevant auth property:

db.define_table('mytable',
    ...,
    Field('created_by', default=lambda: auth.user_id))

The lambda function defined above will not be called when the table is defined, but only later when actually creating a record, which presumably will only happen in a controller that has been decorated with @auth.allows_jwt() (and therefore, auth.user will have been populated by that point).

Another option is to force auth.user to be populated in the model file by calling auth.allows_jwt there (it returns a decorator, but since we are not using it as a decorator, we must instead pass it a no-op function and then call the returned function):

auth = Auth(db, jwt = {'secret_key':'...', 'user_param':"email"})
if not auth.user:
    try:
        # If there is a token, this will populate `auth.user`, 
        # `auth.user_id`, and `auth.user_groups` from the token data.
        auth.allows_jwt()(lambda: None)()
    except:
        # An error means the token is absent, expired, or invalid.
        pass

Once the above has been executed, you can then use auth.user and auth.user_id to specify field defaults in model definitions.

Upvotes: 1

Related Questions