Open samib6 opened 4 years ago
The sample in the docs simply doesn't work. (I stumbled across this as well.) But you should be able to modify the below to work for you:
from authlib.integrations.django_client.integration import token_update
from django.dispatch import receiver
import pendulum
import logging
logger = logging.getLogger(__name__)
class TokenManager(models.Manager):
def update_token(self, name, token, refresh_token=None, access_token=None):
logger.debug("Auto-update of token(%s) started", name)
# This assumes the unique name as seen on the model below.
item = self.get(name=name)
# update old token
item.update(token)
logger.debug("Update complete.")
class Token(models.Model):
objects = TokenManager()
name = models.CharField(max_length=20, unique=True)
# Oauth tokens:
token_type = models.CharField(max_length=40)
access_token = models.CharField(max_length=5000)
refresh_token = models.CharField(max_length=5000, null=True)
expires_at = PendulumDateTimeField()
refresh_url = models.URLField(null=True)
def __str__(self):
return f"{self.name}: a_t:{self.access_token[0:4]}..., exp:{self.expires_at}"
def update(self, token):
self.access_token = token["access_token"]
self.refresh_token = token.get("refresh_token")
self.expires_at = pendulum.from_timestamp(token["expires_at"])
self.token_type = token["token_type"]
self.save()
@property
def expired(self):
return self.expires_at < pendulum.now()
@property
def expiration_remaining(self):
return self.expires_at - pendulum.now()
def to_token(self):
return dict(
access_token=self.access_token,
token_type=self.token_type,
refresh_token=self.refresh_token,
expires_at=int(self.expires_at.timestamp()),
)
@receiver(token_update)
def update_token(
name, token, refresh_token=None, access_token=None, **kwargs
): # pylint: disable=unused-argument
Token.objects.update_token(name, token, refresh_token, access_token)
Admittedly I do the update in the manager as I prefer as much as possible for code to be on my model and not elsewhere, in case I want to update it later. So my receiver is just one line redirecting to the manager responsible. (And you probably want to use generic datetimefields, not the pendulum-backed ones I use.)
Also be aware, unless you're on authlib 0.14.3 or later, the django integration is broken for refresh: #193 (If you're using the metadata url)
@dragonpaw can you help me to update the documentation?
@dragonpaw can you help me to update the documentation?
Sure, how can I help?
- @dragonpaw , by any chance, do you also have a Flask example?
Sadly, I do not. And with Flask, the implementation would be entirely dependent what database system you went with. The SqlAlchemy implementation would look nothing like what a mongo backend implementation would look like. (The last time I wrote a Flask app, it was Aerospike for the database...)
@aFluxx did you manage to make it work with the Flask App?
@aFluxx I have the same question as @verdan. I am having issues getting this functioning in flask.
In the flask client, Authlib uses current_app
as the signal sender, contrary to the documentation which explicit states, "Never pass current_app as sender to a signal." (https://flask.palletsprojects.com/en/2.1.x/signals/?highlight=signals#sending-signals). As explained in the references documentation, Authlib should be using current_app._get_current_object()
as the sender instead. The effective result is that Authlib currently does not reliably support signals in the flask client.
I am trying to use signal for automatic token update . As mentioned in the docs we can use signals to do so. Here is my code for the client in Django.
have added the update_token parameter inside oauth register function.Also the refresh_token_url. But token is not being updated after the respective expire_in time. Am I missing out something ?