refresh_token

Table of Contents


Introdução

Nesse artigo irei continuar o assunto abordado na publicação Email com Google Authentication.

Visto que no primeiro estágio fizemos apenas uma autenticação, nos deparamos com a criação de um arquivo chamado token.json. Nele, está contido uma sequência de informações, sendo elas um token de autenticação, algumas informações do usuário autenticado, e uma data de expiração. Então, quando o usuário utilizar a aplicação que criamos, ele não utilizará mais o arquivo credentias.json, mas sim as informações contidas no token.json.

As informações contidas do token.json serão semelhantes aos dados abaixo.

{
    "scopes": ["https://mail.google.com/"],
    "token_uri": "https://oauth2.googleapis.com/token",
    "expiry": "2022-05-21T00:49:13.081000Z",
    "token": "ya29.a0ARrdaM_Egt-trkKacPEcWEzCC9Lejs7DTo8VnPYRu",
    "client_id": "725031891889-0533ns1pin5753k.apps.googleusercontent.com",
    "client_secret": "GOCSPX-VlvdZsYe-0GXpkctKmK",
    "refresh_token": "1//0h0y8XEIbzPbiCgYIARAAGBESNwF-C7yWA9JaFT_fACew"
}

Como podemos notar, nesse token que nos é retornado há uma data de expiração. Caso o usuário fique enviando vários e-mails durante o dia, terá que passar pela tela de autenticação inumeras vezes, sendo que a Google disponibiliza apenas 4 horas de validade para cada token.

Visto isso, utilizaremos uma informação contida no token.json chamada refresh_token. Com ela, conseguimos criar um novo token de acesso, sem que o usuário precise passar pela tela do browser.

Pré-requisitos

Step 1 – Instalação de bibliotecas

pip install --upgrade jsonlib DateTime requests

Step 2 – Leitura do token.json

Para entender quando iremos criar um novo token de acesso, nos basear pela data de expiração contida no arquivo. Será necessário apontarmos uma variável chamada date_time_now, que irá conter a data/hora atual. Após isso, iremos ler esse token.json, e verificar se a data/hora atual é maior que a data de expiração. Caso sejam, invocaremos uma função chamada de refresh_token.

Todas as informações lidas do arquivo token.json serão atribuída à variável Info_json, que passaremos como parâmetro para a nova função criada.

    if os.path.exists('token.json'):
        with open('token.json', 'r') as verify:
            info_json = json.load(verify)

            if date_time_now > info_json['expiry']:
                refresh_token(info_json)

        creds = Credentials.from_authorized_user_file(
            'token.json', SCOPES)

Step 3 – Função refresh_token

A função refresh_token será responsável por requisitar à API do Google um novo token de acesso. Dentro dessa função será feita toda a manipulação de requisição de um novo token, adição de horas de expiração, e escrita das novas informações dentro do arquivo já existente token.json.

Primeiramente precisaremos criar o corpo da requisição, seguindo alguns padrões exigidos.

def refresh_token(info_json):
    try:
        refresh_token_obj = {
            "client_id": str(info_json["client_id"]).replace("u'", "'"),
            "client_secret": str(info_json["client_secret"]).replace("u'", "'"),
            "refresh_token": str(info_json["refresh_token"]).replace("u'", "'"), 
            "grant_type": "refresh_token"
        }

Logo abaixo, vamos reservar uma variável chamada refresh_credentials. para ela, posteriormente atribuiremos uma nova função nomeada de request_refresh_token, passando como parâmetro as informações que criamos na variável refresh_token_obj.

Após isso, a função request_refresh_token retornará um response. Iremos carregar as informações em formato json na variável refresh_toke_obj. Separaremos mais duas informações, uma variável contendo a soma do horário atual + 4 horas, visto que o token é válido por quatro horas, e também o token de acesso retornado da requisição refresh_credentials.

   refresh_credentials = request_refresh_token(refresh_token_obj)

        refresh_toke_obj = json.loads(refresh_credentials.text)
        expiry_time_refresh_token = datetime.now() + timedelta(hours=4)
        access_token = refresh_toke_obj['access_token']

Por fim, uma exception da função caso ocorra falha em alguma dessas informações que manipulamos.

    except Exception as error:
        print('Erro criacao de refresh_token.\n{}'.format(str(error)))

Step 4 – Função request_refresh_token

O que abordaremos agora será a função itada anteriormente, a request_refresh_token. Nela, iremos apenas fazer uma requisição post para a url https://oauth2.googleapis.com/token, passando as informações que montamos na variável refresh_token_obj anteriormente.

def request_refresh_token(refresh_token_obj):
    try:
        return requests.post('https://oauth2.googleapis.com/token', data=refresh_token_obj)

Assim, finalizaremos com uma sequência de possíveis exceções que podem ocorrem na requisição.

    except requests.exceptions.Timeout as e:
        print('Request Timeout exception:\n{}'.format(v))
        return
    except requests.exceptions.TooManyRedirects as e:
        print('Request too many redirects exception:\n{}'.format(str(e)))
        return
    except requests.exceptions.RequestException as e:
        print('Request exception:\n{}'.format(str(e)))
        return

Step 5 – Execução

O funcionamento será o mesmo mostrado no artigo Email com Google Authentication. Executando o arquivo SendEmail.py, abrirá uma página de seleção de usuário para autenticação.

img1

Como meu aplicativo não foi publicado, irá aparecer uma tela de verificação para aceitar o acesso as informações confidenciais da conta do google que desejamos autenticar.

img2

img3

img4

Após isso, a conexão será autenticada e o email será enviado ao destinatário.

img5

Depois de o usuário passar por esse estágio de autenticação, não precisará mais refazer todos esses passos, visto que a atualização que fizemos no código já irá gerar novos tokens automaticamente.

Código Completo

Code - Email com Google Authentication – Refresh Token

Conclusão

Nesse artigo abordamos a segunda etapa para aplicação de autenticação utilizando Gmail API. Foi mostrado como verificar a validade do token de acesso através da data de expiração. Caso esse token esteja expirado, criamos duas novas funções chamadas de refresh_token e request_refresh_token, responsáveis por requisitar um novo token de acesso, e inseri-lo no arquivo token.json com uma nova data de expiração. Assim, o usuário não precisará ficar passando pelas telas de Login com o Google diversas vezes ao dia. Tudo isso a nova atualização no código fará em back-end para o usuário.

Reforçando o que citei no artigo anterior: Existem outros métodos de autenticação de usuário, e diferentes formas de desenvolver o código para a autenticação, basta saber fazer a procura certa no google que encontrará.

Espero que tenha gostado dessa publicação, e que possa usá-la de alguma forma em seu dia a dia.

Referências

Apps menos seguros e a Conta do Google);

Create a Google Cloud project;

Create access credentials;

Python Quickstart;

Sending Email.