用于从 Heroku 服务器中的电报机器人发帖的 Blogger 的 oauth2client
oauth2client for Blogger posting from a telegram bot in Heroku server
我刚刚在 Heroku 中使用 python-telegram-bot 部署了我的电报机器人。
我的 webhooks 机器人使用 blogger 发布某些内容。到目前为止,我使用模块 google_apli_client.
的 sample_tools 的自定义版本进行了轻微修改
my_tools:
"""
dependencies:
pip3 install --upgrade google-api-python-client
This is a slightly modified implementation
for substituting googleapiclient.sample_tools. It helps customizing some paths
for my project files under different environments
"""
from __future__ import absolute_import
from environments import get_active_env
__all__ = ['init']
import argparse
import os
from googleapiclient import discovery
from googleapiclient.http import build_http
from oauth2client import tools, file, client
def init(argv, name, version, doc, scope=None, parents=[],
discovery_filename=None):
"""A common initialization routine for samples.
Many of the sample applications do the same initialization, which has now
been consolidated into this function. This function uses common idioms found
in almost all the samples, i.e. for an API with name 'apiname', the
credentials are stored in a file named apiname.dat, and the
client_secrets.json file is stored in the same directory as the application
main file.
Args:
argv: list of string, the command-line parameters of the application.
name: string, name of the API.
version: string, version of the API.
doc: string, description of the application. Usually set to __doc__.
file: string, filename of the application. Usually set to __file__.
parents: list of argparse.ArgumentParser, additional command-line flags.
scope: string, The OAuth scope used.
discovery_filename: string, name of local discovery file (JSON). Use
when discovery doc not available via URL.
Returns:
A tuple of (service, flags), where service is the service object and flags
is the parsed command-line flags.
"""
if scope is None:
scope = 'https://www.googleapis.com/auth/' + name
# Parser command-line arguments.
parent_parsers = [tools.argparser]
parent_parsers.extend(parents)
parser = argparse.ArgumentParser(
description=doc,
formatter_class=argparse.RawDescriptionHelpFormatter,
parents=parent_parsers)
flags = parser.parse_args(argv[1:])
# Name of a file containing the OAuth 2.0 information for this
# application, including client_id and client_secret, which are found
# on the API Access tab on the Google APIs
# Console <http://code.google.com/apis/console>.
client_secrets = os.path.join(os.path.dirname(__file__), get_active_env(),
'client_secrets.json')
# Set up a Flow object to be used if we need to authenticate.
flow = client.flow_from_clientsecrets(client_secrets,
scope=scope,
message=tools.message_if_missing(client_secrets))
# Prepare credentials, and authorize HTTP object with them.
# If the credentials don't exist or are invalid,
# run through the native client flow.
# The Storage object will ensure that if successful the good
# credentials will get written back to a file in google_core directory.
storage_file_path = os.path.join(os.path.dirname(__file__), name + '.dat')
storage = file.Storage(storage_file_path)
credentials = storage.get()
if credentials is None or credentials.invalid:
credentials = tools.run_flow(flow, storage, flags)
http = credentials.authorize(http=build_http())
if discovery_filename is None:
# Construct a service object via the discovery service.
service = discovery.build(name,
version,
http=http,
cache_discovery=False)
else:
# Construct a service object using a local discovery document file.
with open(discovery_filename) as discovery_file:
service = discovery.build_from_document(
discovery_file.read(),
base='https://www.googleapis.com/',
http=http)
service = discovery.build(name,
version,
http=http,
cache_discovery=False)
return (service, flags)
有了这个,我可以进行身份验证,OS 中的浏览器会打开并允许我(或最终用户)授权应用程序使用我(或用户的)博客。
初始代码段使用 my_tools:
service, flags = my_tools.init(
[], 'blogger', 'v3', __doc__,
scope='https://www.googleapis.com/auth/blogger')
try:
posts = service.posts()
# This new_post is a custom object, but the important thing here
# is getting the authorization, and then the service at the top
insert = posts.insert(blogId=new_post.blog_id, body=new_post.body(), isDraft=new_post.is_draft)
posts_doc = insert.execute()
return posts_doc
except client.AccessTokenRefreshError:
print('The credentials have been revoked or expired, please re-run the application to re-authorize')
但现在我不能这样做了,因为它在 heroku 中并且日志中出现了这条消息:
app[web.1]: Your browser has been opened to visit:
app[web.1]:
app[web.1]: https://accounts.google.com/o/oauth2/auth?client_id=<client_id>&redirect_uri=http%3A%2F%2Flocalhost%3A8090%2F&scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fblogger&access_type=offline&response_type=code
app[web.1]:
app[web.1]: If your browser is on a different machine then exit and re-run this
app[web.1]: application with the command-line parameter
app[web.1]:
app[web.1]: --noauth_local_webserver
app[web.1]:
我需要自动授权 heroku 应用程序,因为它只能从仅限于某些用户的电报机器人访问,它不需要让用户访问浏览器并授权。
我需要一些方法来允许机器人使用 blogger,并且用户能够通过一种简单的方法在需要时使用机器人进行授权,或者使用已经存储在服务器中的一些授权文件。
我用谷歌搜索并查看了这些资源:
https://developers.google.com/api-client-library/python/auth/web-app
https://github.com/burnash/gspread/wiki/How-to-get-OAuth-access-token-in-console%3F
Django oauth2 google not working on server
但我完全不知道我应该做什么和怎么做。我觉得我需要一个傻瓜式的解释。
已编辑:我已被指向此网站
https://developers.google.com/api-client-library/python/auth/service-accounts
所以我尝试了这个新代码。
新片段:
from oauth2client import service_account
import googleapiclient.discovery
import os
from environments import get_active_env
SERVICE_ACCOUNT_FILE = os.path.join(os.path.dirname(__file__), os.pardir, 'google_core', get_active_env(),
'service_account.json')
credentials = service_account.ServiceAccountCredentials.from_json_keyfile_name(
SERVICE_ACCOUNT_FILE, scopes=['https://www.googleapis.com/auth/blogger'])
service = googleapiclient.discovery.build('blogger', 'v3', credentials=credentials)
try:
posts = service.posts()
insert = posts.insert(blogId=new_post.blog_id, body=new_post.body(), isDraft=new_post.is_draft)
posts_doc = insert.execute()
return posts_doc
except client.AccessTokenRefreshError:
print('The credentials have been revoked or expired, please re-run the application to re-authorize')
所以我现在在日志中得到了这个(我认为 403 HttpError 是这里的问题,关于 memcache 的另一个错误或 oauth2client.contrib.locked_file 没有被导入没什么大不了的):
heroku[web.1]: Unidling
heroku[web.1]: State changed from down to starting
heroku[web.1]: Starting process with command `python my_bot.py`
heroku[web.1]: State changed from starting to up
heroku[router]: at=info method=POST path="/<bot_token>" host=telegram-bot-alfred.herokuapp.com request_id=<request_id> fwd="<ip>" dyno=web.1 connect=1ms service=2ms status=200 bytes=97 protocol=https
app[web.1]: INFO - Input: post_asin
app[web.1]: INFO - Input ASIN: B079Z8THTF
app[web.1]: INFO - Printing offers for asin B079Z8THTF:
app[web.1]: INFO - EUR 36.98
app[web.1]: INFO - URL being requested: GET https://www.googleapis.com/discovery/v1/apis/blogger/v3/rest
app[web.1]: INFO - Attempting refresh to obtain initial access_token
app[web.1]: INFO - URL being requested: POST https://www.googleapis.com/blogger/v3/blogs/2270688467086771731/posts?isDraft=true&alt=json
app[web.1]: INFO - Refreshing access_token
app[web.1]: WARNING - Encountered 403 Forbidden with reason "forbidden"
app[web.1]: ERROR - Error with asin B079Z8THTF. We go to the next.
app[web.1]: Traceback (most recent call last):
app[web.1]: File "my_bot.py", line 171, in process_asin_string
app[web.1]: send_post_to_blogger(update.message, post)
app[web.1]: File "/app/api_samples/blogger/blogger_insert.py", line 85, in send_post_to_blogger
app[web.1]: response = post_at_blogger(post)
app[web.1]: File "/app/api_samples/blogger/blogger_insert.py", line 72, in post_at_blogger
app[web.1]: posts_doc = insert.execute()
app[web.1]: File "/app/.heroku/python/lib/python3.6/site-packages/googleapiclient/http.py", line 844, in execute
app[web.1]: raise HttpError(resp, content, uri=self.uri)
app[web.1]: File "/app/.heroku/python/lib/python3.6/site-packages/oauth2client/_helpers.py", line 133, in positional_wrapper
app[web.1]: return wrapped(*args, **kwargs)
app[web.1]: googleapiclient.errors.HttpError: <HttpError 403 when requesting https://www.googleapis.com/blogger/v3/blogs/2270688467086771731/posts?isDraft=true&alt=json returned "We're sorry, but you don't have permission to access this resource.">
app[web.1]: ERROR - Exception HttpError not handled
app[web.1]: Traceback (most recent call last):
app[web.1]: File "my_bot.py", line 171, in process_asin_string
app[web.1]: send_post_to_blogger(update.message, post)
app[web.1]: File "/app/api_samples/blogger/blogger_insert.py", line 85, in send_post_to_blogger
app[web.1]: response = post_at_blogger(post)
app[web.1]: File "/app/api_samples/blogger/blogger_insert.py", line 72, in post_at_blogger
app[web.1]: posts_doc = insert.execute()
app[web.1]: File "/app/.heroku/python/lib/python3.6/site-packages/googleapiclient/http.py", line 844, in execute
app[web.1]: raise HttpError(resp, content, uri=self.uri)
app[web.1]: File "/app/.heroku/python/lib/python3.6/site-packages/oauth2client/_helpers.py", line 133, in positional_wrapper
app[web.1]: return wrapped(*args, **kwargs)
app[web.1]: googleapiclient.errors.HttpError: <HttpError 403 when requesting https://www.googleapis.com/blogger/v3/blogs/2270688467086771731/posts?isDraft=true&alt=json returned "We're sorry, but you don't have permission to access this resource.">
app[web.1]:
app[web.1]: During handling of the above exception, another exception occurred:
app[web.1]:
app[web.1]: Traceback (most recent call last):
app[web.1]: File "/app/exceptions/errors.py", line 47, in alfred
app[web.1]: message.reply_text(rnd.choice(answers[type(exception)]))
app[web.1]: KeyError: <class 'googleapiclient.errors.HttpError'>
app[web.1]: WARNING - Error with asin B079Z8THTF. We go to the next
我通过提供如下参数找到了解决方案:
service, flags = my_tools.init(
['', '--noauth_local_webserver'], 'blogger', 'v3', __doc__,
scope='https://www.googleapis.com/auth/blogger')
然后我不得不自定义一些来自oauth2client.tools的方法。我在 my_tools 中做了两个方法和附加代码。缺失的每一部分都可以很容易地从原始 google 的工具中导入或复制:
# module scope
import argparse
from googleapiclient import discovery
from googleapiclient.http import build_http
from oauth2client import tools, file, client, _helpers
from oauth2client.tools import _CreateArgumentParser
_GO_TO_LINK_MESSAGE = """
Visit this link to get auth code
{address}
"""
# argparser is an ArgumentParser that contains command-line options expected
# by tools.run(). Pass it in as part of the 'parents' argument to your own
# ArgumentParser.
argparser = _CreateArgumentParser()
_flow = None
# Methods
@_helpers.positional(3)
def run_flow(flow, flags=None):
"""
Emulates the original method run_flow from oauth2client.tools getting the website to visit.
The ``run()`` function is called from your application and runs
through all the steps to obtain credentials. It takes a ``Flow``
argument and attempts to open an authorization server page in the
user's default web browser. The server asks the user to grant your
application access to the user's data. The user can then get an
authentication code for inputing later
:param flow: the google OAuth 2.0 Flow object with which the auth begun
:param flags: the provided flags
:return: the string with the website link where the user can authenticate and obtain a code
"""
global _flow
# I update the _flow object for using internally later
_flow = flow
# Really the flags aren't very used. In practice I copied the method as if noauth_local_webserver was provided
if flags is None:
flags = argparser.parse_args()
logging.getLogger().setLevel(getattr(logging, flags.logging_level))
oauth_callback = client.OOB_CALLBACK_URN
_flow.redirect_uri = oauth_callback
authorize_url = _flow.step1_get_authorize_url()
return _GO_TO_LINK_MESSAGE.format(address=authorize_url)
def oauth_with(code, http=None):
"""
If the code grants access,
the function returns new credentials. The new credentials
are also stored in the ``storage`` argument, which updates the file
associated with the ``Storage`` object.
:param code: the auth code
:param http: the http transport object
:return: the credentials if any
"""
global _flow
storage_file_path = get_credentials_path('blogger')
storage = file.Storage(storage_file_path)
try:
# We now re-use the _flow stored earlier
credential = _flow.step2_exchange(code, http=http)
except client.FlowExchangeError as e:
raise AlfredException(msg='Authentication has failed: {0}'.format(e))
storage.put(credential)
credential.set_store(storage)
# We reset the flow
_flow = None
return credential
我刚刚在 Heroku 中使用 python-telegram-bot 部署了我的电报机器人。
我的 webhooks 机器人使用 blogger 发布某些内容。到目前为止,我使用模块 google_apli_client.
的 sample_tools 的自定义版本进行了轻微修改my_tools:
"""
dependencies:
pip3 install --upgrade google-api-python-client
This is a slightly modified implementation
for substituting googleapiclient.sample_tools. It helps customizing some paths
for my project files under different environments
"""
from __future__ import absolute_import
from environments import get_active_env
__all__ = ['init']
import argparse
import os
from googleapiclient import discovery
from googleapiclient.http import build_http
from oauth2client import tools, file, client
def init(argv, name, version, doc, scope=None, parents=[],
discovery_filename=None):
"""A common initialization routine for samples.
Many of the sample applications do the same initialization, which has now
been consolidated into this function. This function uses common idioms found
in almost all the samples, i.e. for an API with name 'apiname', the
credentials are stored in a file named apiname.dat, and the
client_secrets.json file is stored in the same directory as the application
main file.
Args:
argv: list of string, the command-line parameters of the application.
name: string, name of the API.
version: string, version of the API.
doc: string, description of the application. Usually set to __doc__.
file: string, filename of the application. Usually set to __file__.
parents: list of argparse.ArgumentParser, additional command-line flags.
scope: string, The OAuth scope used.
discovery_filename: string, name of local discovery file (JSON). Use
when discovery doc not available via URL.
Returns:
A tuple of (service, flags), where service is the service object and flags
is the parsed command-line flags.
"""
if scope is None:
scope = 'https://www.googleapis.com/auth/' + name
# Parser command-line arguments.
parent_parsers = [tools.argparser]
parent_parsers.extend(parents)
parser = argparse.ArgumentParser(
description=doc,
formatter_class=argparse.RawDescriptionHelpFormatter,
parents=parent_parsers)
flags = parser.parse_args(argv[1:])
# Name of a file containing the OAuth 2.0 information for this
# application, including client_id and client_secret, which are found
# on the API Access tab on the Google APIs
# Console <http://code.google.com/apis/console>.
client_secrets = os.path.join(os.path.dirname(__file__), get_active_env(),
'client_secrets.json')
# Set up a Flow object to be used if we need to authenticate.
flow = client.flow_from_clientsecrets(client_secrets,
scope=scope,
message=tools.message_if_missing(client_secrets))
# Prepare credentials, and authorize HTTP object with them.
# If the credentials don't exist or are invalid,
# run through the native client flow.
# The Storage object will ensure that if successful the good
# credentials will get written back to a file in google_core directory.
storage_file_path = os.path.join(os.path.dirname(__file__), name + '.dat')
storage = file.Storage(storage_file_path)
credentials = storage.get()
if credentials is None or credentials.invalid:
credentials = tools.run_flow(flow, storage, flags)
http = credentials.authorize(http=build_http())
if discovery_filename is None:
# Construct a service object via the discovery service.
service = discovery.build(name,
version,
http=http,
cache_discovery=False)
else:
# Construct a service object using a local discovery document file.
with open(discovery_filename) as discovery_file:
service = discovery.build_from_document(
discovery_file.read(),
base='https://www.googleapis.com/',
http=http)
service = discovery.build(name,
version,
http=http,
cache_discovery=False)
return (service, flags)
有了这个,我可以进行身份验证,OS 中的浏览器会打开并允许我(或最终用户)授权应用程序使用我(或用户的)博客。
初始代码段使用 my_tools:
service, flags = my_tools.init(
[], 'blogger', 'v3', __doc__,
scope='https://www.googleapis.com/auth/blogger')
try:
posts = service.posts()
# This new_post is a custom object, but the important thing here
# is getting the authorization, and then the service at the top
insert = posts.insert(blogId=new_post.blog_id, body=new_post.body(), isDraft=new_post.is_draft)
posts_doc = insert.execute()
return posts_doc
except client.AccessTokenRefreshError:
print('The credentials have been revoked or expired, please re-run the application to re-authorize')
但现在我不能这样做了,因为它在 heroku 中并且日志中出现了这条消息:
app[web.1]: Your browser has been opened to visit:
app[web.1]:
app[web.1]: https://accounts.google.com/o/oauth2/auth?client_id=<client_id>&redirect_uri=http%3A%2F%2Flocalhost%3A8090%2F&scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fblogger&access_type=offline&response_type=code
app[web.1]:
app[web.1]: If your browser is on a different machine then exit and re-run this
app[web.1]: application with the command-line parameter
app[web.1]:
app[web.1]: --noauth_local_webserver
app[web.1]:
我需要自动授权 heroku 应用程序,因为它只能从仅限于某些用户的电报机器人访问,它不需要让用户访问浏览器并授权。
我需要一些方法来允许机器人使用 blogger,并且用户能够通过一种简单的方法在需要时使用机器人进行授权,或者使用已经存储在服务器中的一些授权文件。
我用谷歌搜索并查看了这些资源:
https://developers.google.com/api-client-library/python/auth/web-app https://github.com/burnash/gspread/wiki/How-to-get-OAuth-access-token-in-console%3F Django oauth2 google not working on server
但我完全不知道我应该做什么和怎么做。我觉得我需要一个傻瓜式的解释。
已编辑:我已被指向此网站
https://developers.google.com/api-client-library/python/auth/service-accounts
所以我尝试了这个新代码。
新片段:
from oauth2client import service_account
import googleapiclient.discovery
import os
from environments import get_active_env
SERVICE_ACCOUNT_FILE = os.path.join(os.path.dirname(__file__), os.pardir, 'google_core', get_active_env(),
'service_account.json')
credentials = service_account.ServiceAccountCredentials.from_json_keyfile_name(
SERVICE_ACCOUNT_FILE, scopes=['https://www.googleapis.com/auth/blogger'])
service = googleapiclient.discovery.build('blogger', 'v3', credentials=credentials)
try:
posts = service.posts()
insert = posts.insert(blogId=new_post.blog_id, body=new_post.body(), isDraft=new_post.is_draft)
posts_doc = insert.execute()
return posts_doc
except client.AccessTokenRefreshError:
print('The credentials have been revoked or expired, please re-run the application to re-authorize')
所以我现在在日志中得到了这个(我认为 403 HttpError 是这里的问题,关于 memcache 的另一个错误或 oauth2client.contrib.locked_file 没有被导入没什么大不了的):
heroku[web.1]: Unidling
heroku[web.1]: State changed from down to starting
heroku[web.1]: Starting process with command `python my_bot.py`
heroku[web.1]: State changed from starting to up
heroku[router]: at=info method=POST path="/<bot_token>" host=telegram-bot-alfred.herokuapp.com request_id=<request_id> fwd="<ip>" dyno=web.1 connect=1ms service=2ms status=200 bytes=97 protocol=https
app[web.1]: INFO - Input: post_asin
app[web.1]: INFO - Input ASIN: B079Z8THTF
app[web.1]: INFO - Printing offers for asin B079Z8THTF:
app[web.1]: INFO - EUR 36.98
app[web.1]: INFO - URL being requested: GET https://www.googleapis.com/discovery/v1/apis/blogger/v3/rest
app[web.1]: INFO - Attempting refresh to obtain initial access_token
app[web.1]: INFO - URL being requested: POST https://www.googleapis.com/blogger/v3/blogs/2270688467086771731/posts?isDraft=true&alt=json
app[web.1]: INFO - Refreshing access_token
app[web.1]: WARNING - Encountered 403 Forbidden with reason "forbidden"
app[web.1]: ERROR - Error with asin B079Z8THTF. We go to the next.
app[web.1]: Traceback (most recent call last):
app[web.1]: File "my_bot.py", line 171, in process_asin_string
app[web.1]: send_post_to_blogger(update.message, post)
app[web.1]: File "/app/api_samples/blogger/blogger_insert.py", line 85, in send_post_to_blogger
app[web.1]: response = post_at_blogger(post)
app[web.1]: File "/app/api_samples/blogger/blogger_insert.py", line 72, in post_at_blogger
app[web.1]: posts_doc = insert.execute()
app[web.1]: File "/app/.heroku/python/lib/python3.6/site-packages/googleapiclient/http.py", line 844, in execute
app[web.1]: raise HttpError(resp, content, uri=self.uri)
app[web.1]: File "/app/.heroku/python/lib/python3.6/site-packages/oauth2client/_helpers.py", line 133, in positional_wrapper
app[web.1]: return wrapped(*args, **kwargs)
app[web.1]: googleapiclient.errors.HttpError: <HttpError 403 when requesting https://www.googleapis.com/blogger/v3/blogs/2270688467086771731/posts?isDraft=true&alt=json returned "We're sorry, but you don't have permission to access this resource.">
app[web.1]: ERROR - Exception HttpError not handled
app[web.1]: Traceback (most recent call last):
app[web.1]: File "my_bot.py", line 171, in process_asin_string
app[web.1]: send_post_to_blogger(update.message, post)
app[web.1]: File "/app/api_samples/blogger/blogger_insert.py", line 85, in send_post_to_blogger
app[web.1]: response = post_at_blogger(post)
app[web.1]: File "/app/api_samples/blogger/blogger_insert.py", line 72, in post_at_blogger
app[web.1]: posts_doc = insert.execute()
app[web.1]: File "/app/.heroku/python/lib/python3.6/site-packages/googleapiclient/http.py", line 844, in execute
app[web.1]: raise HttpError(resp, content, uri=self.uri)
app[web.1]: File "/app/.heroku/python/lib/python3.6/site-packages/oauth2client/_helpers.py", line 133, in positional_wrapper
app[web.1]: return wrapped(*args, **kwargs)
app[web.1]: googleapiclient.errors.HttpError: <HttpError 403 when requesting https://www.googleapis.com/blogger/v3/blogs/2270688467086771731/posts?isDraft=true&alt=json returned "We're sorry, but you don't have permission to access this resource.">
app[web.1]:
app[web.1]: During handling of the above exception, another exception occurred:
app[web.1]:
app[web.1]: Traceback (most recent call last):
app[web.1]: File "/app/exceptions/errors.py", line 47, in alfred
app[web.1]: message.reply_text(rnd.choice(answers[type(exception)]))
app[web.1]: KeyError: <class 'googleapiclient.errors.HttpError'>
app[web.1]: WARNING - Error with asin B079Z8THTF. We go to the next
我通过提供如下参数找到了解决方案:
service, flags = my_tools.init(
['', '--noauth_local_webserver'], 'blogger', 'v3', __doc__,
scope='https://www.googleapis.com/auth/blogger')
然后我不得不自定义一些来自oauth2client.tools的方法。我在 my_tools 中做了两个方法和附加代码。缺失的每一部分都可以很容易地从原始 google 的工具中导入或复制:
# module scope
import argparse
from googleapiclient import discovery
from googleapiclient.http import build_http
from oauth2client import tools, file, client, _helpers
from oauth2client.tools import _CreateArgumentParser
_GO_TO_LINK_MESSAGE = """
Visit this link to get auth code
{address}
"""
# argparser is an ArgumentParser that contains command-line options expected
# by tools.run(). Pass it in as part of the 'parents' argument to your own
# ArgumentParser.
argparser = _CreateArgumentParser()
_flow = None
# Methods
@_helpers.positional(3)
def run_flow(flow, flags=None):
"""
Emulates the original method run_flow from oauth2client.tools getting the website to visit.
The ``run()`` function is called from your application and runs
through all the steps to obtain credentials. It takes a ``Flow``
argument and attempts to open an authorization server page in the
user's default web browser. The server asks the user to grant your
application access to the user's data. The user can then get an
authentication code for inputing later
:param flow: the google OAuth 2.0 Flow object with which the auth begun
:param flags: the provided flags
:return: the string with the website link where the user can authenticate and obtain a code
"""
global _flow
# I update the _flow object for using internally later
_flow = flow
# Really the flags aren't very used. In practice I copied the method as if noauth_local_webserver was provided
if flags is None:
flags = argparser.parse_args()
logging.getLogger().setLevel(getattr(logging, flags.logging_level))
oauth_callback = client.OOB_CALLBACK_URN
_flow.redirect_uri = oauth_callback
authorize_url = _flow.step1_get_authorize_url()
return _GO_TO_LINK_MESSAGE.format(address=authorize_url)
def oauth_with(code, http=None):
"""
If the code grants access,
the function returns new credentials. The new credentials
are also stored in the ``storage`` argument, which updates the file
associated with the ``Storage`` object.
:param code: the auth code
:param http: the http transport object
:return: the credentials if any
"""
global _flow
storage_file_path = get_credentials_path('blogger')
storage = file.Storage(storage_file_path)
try:
# We now re-use the _flow stored earlier
credential = _flow.step2_exchange(code, http=http)
except client.FlowExchangeError as e:
raise AlfredException(msg='Authentication has failed: {0}'.format(e))
storage.put(credential)
credential.set_store(storage)
# We reset the flow
_flow = None
return credential