5

Questo post è un seguito per How to make 'access_type=offline'/server-only OAuth2 operations on GAE/Python. La parte http = credentials.authorize(httplib2.Http()) non fallisce più quando si prova, ma sembra che ancora non se eseguito da cron di GAE, dove è in grado di aggiornare il mio access_token:Come evitare 'Impossibile recuperare il token di accesso: {"errore": "invalid_grant"}' nelle attività di cron GAE offline?

  1. posso eseguire manualmente il mio lavoro chiamando /fetch, dire alle 11:45 .
  2. La pianificazione immediata di un lavoro /cronfetch alle 11:55 funziona quindi, senza alcun problema access_token.
  3. Ma poi, mi sono svegliato questa mattina, visto che lo stesso/cronfetch compito (stesso, tranne il tempo, che è alle 01:00 per il mio non-test compito quotidiano) non è riuscita:

    I 2013-06-10 05:53:51.324 make: Got type <class 'google.appengine.api.datastore_types.Blob'> 
    I 2013-06-10 05:53:51.325 validate: Got type <class 'oauth2client.client.OAuth2Credentials'> 
    I 2013-06-10 05:53:51.327 URL being requested: https://www.googleapis.com/youtube/v3/playlists?alt=json&part=snippet%2Cstatus 
    I 2013-06-10 05:53:51.397 Refreshing due to a 401 
    I 2013-06-10 05:53:51.420 make: Got type <class 'google.appengine.api.datastore_types.Blob'> 
    I 2013-06-10 05:53:51.421 validate: Got type <class 'oauth2client.client.OAuth2Credentials'> 
    I 2013-06-10 05:53:51.421 Refreshing access_token 
    I 2013-06-10 05:53:51.458 Failed to retrieve access token: { "error" : "invalid_grant" } 
    I 2013-06-10 05:53:51.468 make: Got type <class 'google.appengine.api.datastore_types.Blob'> 
    I 2013-06-10 05:53:51.468 validate: Got type <class 'oauth2client.client.OAuth2Credentials'> 
    I 2013-06-10 05:53:51.471 validate: Got type <class 'oauth2client.client.OAuth2Credentials'> 
    I 2013-06-10 05:53:51.471 get: Got type <class 'oauth2client.appengine.CredentialsModel'> 
    E 2013-06-10 05:53:51.480 invalid_grant Traceback (most recent call last): File "/python27_runtime/python27_lib/versions/third_party/webapp2-2.5.2/webapp2.py", line 1535, in 
    

Questo messaggio di posta elettronica Getting "invalid_grant" error on token refresh (+ SO post 1, SO post 2, SO post 3) assomiglia al mio problema, ma sembra che si stia verificando un token access_type=online. Nel mio caso uso solo il valore predefinito access_type=offline e vedo lo "Esegui queste operazioni quando non utilizzo l'applicazione" menzionato nella richiesta di accesso iniziale.

ho appena ri-programmato una corsa cron a 08:25 (facendo attenzione a non lanciare uno manuale) con le dichiarazioni di debug di stampa che mi sono impegnata a GitHub per voi. Ecco cosa ottengo, è simile ma non identico (si noti che le ultime poche righe sembrano ordinate in modo errato, io sicuramente non sto facendo roba OAuth2 in create_playlist fino a quando non vengono letti tutti i sorgenti). Così ignorando l'ordine obliquo (? GAE registrazione artefatto), sembra my http = credentials.authorize(Http()) call in create_playlist(self), currently at line 144 è sbagliato:

... 
    E 2013-06-10 08:26:12.817 http://www.onedayonemusic.com/page/2/ : found embeds ['80wWl_s-HuQ', 'kb1Nu75l1vA', 'kb1Nu75l1vA', 'RTWcNRQtkwE', 'RTWcNRQtkwE', 'ZtDXezAhes8', 'ZtDXezAhes8', 'cFGxNJhKK9c', 'cFGxNJhKK9c' 
    I 2013-06-10 08:26:14.019 make: Got type <class 'google.appengine.api.datastore_types.Blob'> 
    I 2013-06-10 08:26:14.020 validate: Got type <class 'oauth2client.client.OAuth2Credentials'> 
    I 2013-06-10 08:26:14.022 URL being requested: https://www.googleapis.com/youtube/v3/playlists?alt=json&part=snippet%2Cstatus 
    I 2013-06-10 08:26:14.100 Refreshing due to a 401 
    I 2013-06-10 08:26:14.105 make: Got type <class 'google.appengine.api.datastore_types.Blob'> 
    I 2013-06-10 08:26:14.106 validate: Got type <class 'oauth2client.client.OAuth2Credentials'> 
    I 2013-06-10 08:26:14.106 Refreshing access_token 
    E 2013-06-10 08:26:18.994 Deadline exceeded while waiting for HTTP response from URL: https://accounts.google.com/o/oauth2/token Traceback (most recent call last): File "/pyt 
    E 2013-06-10 08:26:18.996 http://www.onedayonemusic.com/page/3/ : found embeds ['80wWl_s-HuQ', '6VNu2MLdE0c', '6VNu2MLdE0c', 'YwQilKbK9Mk', 'YwQilKbK9Mk', 'KYdB3rectmc', 'KYdB3 
    E 2013-06-10 08:26:18.996 crawl_videos end 
    E 2013-06-10 08:26:18.996 create_playlist start 
    E 2013-06-10 08:26:18.996 create_playlist got creds 
    E 2013-06-10 08:26:18.996 create_playlist authorized creds 

→ Perché il cron lavoro lavoro 5min dopo una corsa manuale, ma fallisce sei ore più tardi? Pensavo che il token di aggiornamento non fosse mai scaduto. Che cosa sto facendo di sbagliato?

Si noti che il mio primo lavoro GAE, e il mio secondo programma Python a tutti, la revisione del codice generale/consiglio è molto gradito, ma cerca di essere gentile :)

Il codice è il GitHub e il mio esempio può essere raggiunto a dailygrooves.org . Grazie per l'aiuto!

risposta

3

Un invalid_grant viene restituito quando il token di aggiornamento non può essere utilizzato per ottenere un nuovo token di accesso dall'attuale utente. Questo sta accadendo a voi perché la stored Credentials oggetto ha un token di aggiornamento nullo, cioè

>>> credentials.refresh_token is None 
True 

Come accennato nella NOTA in How to make 'access_type=offline'/server-only OAuth2 operations on GAE/Python?:

Se un utente ha già autorizzato il tuo ID cliente, le volte successive che esegui OAuth per questi utenti non visualizzeranno la finestra di dialogo OAuth e non ti verrà fornito un token di aggiornamento.

È necessario assicurarsi che il proprio Credentials vengono memorizzati con un aggiornamento gettone valido e il modo più semplice per farlo, come indicato nella sua ultima domanda, così come in tutte le 3 domande che legato è quello di utilizzare al approval_prompt=force durante la creazione di l'oggetto OAuth2WebServerFlow o OAuth2Decorator (a seconda di quale si sta utilizzando).

+0

OK, ho pensato che non mi servisse, perché il mio compito cron funzionava una volta! In che modo la stessa attività di cron può funzionare pochi minuti dopo un'operazione manuale, ma fallisce 6 ore dopo? E una seconda domanda: dal momento che sto usando 'OAuth2DecoratorFromClientSecrets', che non inoltra ulteriori' ** kwargs' a 'OAuth2Decorator', come consiglia di impostare il mio parametro aggiuntivo' approval_prompt = force'? Deve essere fatto al momento di init, o va bene se creo il mio 'decorator = OAuth2DecoratorFromClientSecrets ...' e dopo 'decorator.params.update ({approval_prompt = 'force'})'? Grazie. –

+1

L'attività cron funzionerà quando 'credentials.access_token' è valido, ma il token di accesso scadrà dopo 1 ora. Dopo la scadenza, 'credentials.refresh_token' è necessario per ottenere un nuovo token di accesso. Vorresti 'decorator.params.update ({'approval_prompt': 'force'})' ma non c'è una buona ragione per non passarlo al costruttore. – bossylobster

+0

OK, non sapevo del limite di 1 ora, grazie. Per quanto riguarda * "non c'è una buona ragione per non passare semplicemente al costruttore" *, beh, mi piacerebbe! Ma 'OAuth2DecoratorFromClientSecrets' non sembra onorare/inoltrare ulteriori' ** kwargs' (questo è quello che capisco dalla fonte e l'eccezione che getta se provo), quindi la mia domanda. Mi sto perdendo qualcosa? –

Problemi correlati