예제 #1
0
def nokia_auth():
    print('First we need your Client ID, Consumer Secret, and Callback URI')
    print(
        'You can find it here: https://account.withings.com/partner/dashboard_oauth2'
    )
    client_id = input('client_id: ')
    consumer_secret = input('consumer_secret: ')
    callback_uri = input('callback_uri: ')

    auth = NokiaAuth(client_id, consumer_secret, callback_uri=callback_uri)
    authorize_url = auth.get_authorize_url()
    print(
        'Now you should open this authorization URL and give the app access: ')
    print(authorize_url)
    auth_url = input('Enter the response URL: ')

    # We have to parse the URL to extract the code from the query string
    u = urlparse(auth_url)
    auth_code = parse_qs(u.query)['code'][0]
    creds = auth.get_credentials(auth_code)

    # Save this so we don't have to do this again
    save_creds(creds)

    # Pass back
    return creds
예제 #2
0
 def test_get_authorize_url(self):
     """ Make sure the get_authorize_url function works as expected """
     auth = NokiaAuth(*self.auth_args, callback_uri=self.callback_uri)
     # Returns the OAuth2Session.authorization_url results
     self.assertEqual(auth.get_authorize_url(), 'URL')
     OAuth2Session.authorization_url.assert_called_once_with(
         '{}/oauth2_user/authorize2'.format(NokiaAuth.URL))
예제 #3
0
 def test_get_authorize_url(self):
     """ Make sure the get_authorize_url function works as expected """
     auth = NokiaAuth(*self.auth_args, callback_uri=self.callback_uri)
     # Returns the OAuth2Session.authorization_url results
     self.assertEqual(auth.get_authorize_url(), 'URL')
     OAuth2Session.authorization_url.assert_called_once_with(
         '{}/oauth2_user/authorize2'.format(NokiaAuth.URL)
     )
예제 #4
0
 def test_get_authorize_url(self):
     """ Make sure the get_authorize_url function works as expected """
     auth = NokiaAuth(self.consumer_key, self.consumer_secret)
     # Returns the OAuth1Session.authorization_url results
     self.assertEqual(auth.get_authorize_url(), 'URL')
     # oauth_token and oauth_secret have now been set to the values
     # returned by OAuth1Session.fetch_request_token
     self.assertEqual(auth.oauth_token, 'fake_oauth_token')
     self.assertEqual(auth.oauth_secret, 'fake_oauth_token_secret')
예제 #5
0
    def test_migrate_from_oauth1(self):
        """ Make sure the migrate_from_oauth1 fucntion works as expected """
        Session.request = MagicMock()
        auth = NokiaAuth(*self.auth_args)

        token = auth.migrate_from_oauth1('at', 'ats')

        self.assertEqual(token, self.token)
        OAuth2Session.refresh_token.assert_called_once_with(
            '{}/oauth2/token'.format(NokiaAuth.URL), refresh_token='at:ats')
예제 #6
0
    def test_migrate_from_oauth1(self):
        """ Make sure the migrate_from_oauth1 fucntion works as expected """
        Session.request = MagicMock()
        auth = NokiaAuth(*self.auth_args)

        token = auth.migrate_from_oauth1('at', 'ats')

        self.assertEqual(token, self.token)
        OAuth2Session.refresh_token.assert_called_once_with(
            '{}/oauth2/token'.format(NokiaAuth.URL),
            refresh_token='at:ats'
        )
예제 #7
0
 def test_get_credentials(self):
     """ Make sure the get_credentials function works as expected """
     auth = NokiaAuth(self.consumer_key, self.consumer_secret)
     # Returns an authorized NokiaCredentials object
     creds = auth.get_credentials('FAKE_OAUTH_VERIFIER')
     assert isinstance(creds, NokiaCredentials)
     # Check that the attributes of the NokiaCredentials object are
     # correct.
     self.assertEqual(creds.access_token, 'fake_oauth_token')
     self.assertEqual(creds.access_token_secret, 'fake_oauth_token_secret')
     self.assertEqual(creds.consumer_key, self.consumer_key)
     self.assertEqual(creds.consumer_secret, self.consumer_secret)
     self.assertEqual(creds.user_id, 'FAKEID')
예제 #8
0
 def test_attribute_defaults(self):
     """ Make sure NokiaAuth attributes have the proper defaults """
     self.assertEqual(NokiaAuth.URL,
                      'https://developer.health.nokia.com/account')
     auth = NokiaAuth(self.consumer_key, self.consumer_secret)
     self.assertEqual(auth.oauth_token, None)
     self.assertEqual(auth.oauth_secret, None)
예제 #9
0
 def test_get_credentials(self):
     """ Make sure the get_credentials function works as expected """
     auth = NokiaAuth(*self.auth_args, callback_uri=self.callback_uri)
     # Returns an authorized NokiaCredentials object
     creds = auth.get_credentials('FAKE_CODE')
     assert isinstance(creds, NokiaCredentials)
     # Check that the attributes of the NokiaCredentials object are
     # correct.
     self.assertEqual(creds.access_token, 'fake_access_token')
     self.assertEqual(creds.token_expiry, str(int((
         datetime.datetime.utcnow() - datetime.datetime(1970, 1, 1)
     ).total_seconds())))
     self.assertEqual(creds.token_type, 'Bearer')
     self.assertEqual(creds.refresh_token, 'fake_refresh_token')
     self.assertEqual(creds.client_id, self.client_id)
     self.assertEqual(creds.consumer_secret, self.consumer_secret)
     self.assertEqual(creds.user_id, 'fake_user_id')
예제 #10
0
 def test_attributes(self):
     """ Make sure the NokiaAuth objects have the right attributes """
     assert hasattr(NokiaAuth, 'URL')
     auth = NokiaAuth(self.consumer_key, self.consumer_secret)
     assert hasattr(auth, 'consumer_key')
     self.assertEqual(auth.consumer_key, self.consumer_key)
     assert hasattr(auth, 'consumer_secret')
     self.assertEqual(auth.consumer_secret, self.consumer_secret)
예제 #11
0
 def test_get_credentials(self):
     """ Make sure the get_credentials function works as expected """
     auth = NokiaAuth(*self.auth_args, callback_uri=self.callback_uri)
     # Returns an authorized NokiaCredentials object
     creds = auth.get_credentials('FAKE_CODE')
     assert isinstance(creds, NokiaCredentials)
     # Check that the attributes of the NokiaCredentials object are
     # correct.
     self.assertEqual(creds.access_token, 'fake_access_token')
     self.assertEqual(
         creds.token_expiry,
         str(
             int((datetime.datetime.utcnow() -
                  datetime.datetime(1970, 1, 1)).total_seconds())))
     self.assertEqual(creds.token_type, 'Bearer')
     self.assertEqual(creds.refresh_token, 'fake_refresh_token')
     self.assertEqual(creds.client_id, self.client_id)
     self.assertEqual(creds.consumer_secret, self.consumer_secret)
     self.assertEqual(creds.user_id, 'fake_user_id')
def migrate_to_oauth2(apps, schema_editor):
    NokiaUser = apps.get_model("nokiaapp", "NokiaUser")
    auth = NokiaAuth(
        get_setting('NOKIA_CLIENT_ID'), get_setting('NOKIA_CONSUMER_SECRET'))
    for user in NokiaUser.objects.all():
        try:
            token = auth.migrate_from_oauth1(
                user.access_token,
                user.access_token_secret
            )
            user.access_token = token['access_token']
            user.token_expiry = int((
                datetime.datetime.utcnow() - datetime.datetime(1970, 1, 1)
            ).total_seconds()) + int(token['expires_in'])
            user.token_type = token['token_type']
            user.refresh_token = token['refresh_token']
            user.save()
        except:
            # Problem with existing token
            user.delete()
예제 #13
0
파일: settings.py 프로젝트: snowind/fitly
def check_withings_connection():
    # If not connected, send to auth app page to start token request
    if not withings_connected():
        return html.A(className='text-center col-lg-12', children=[
            dbc.Button('Connect Withings', id='connect-withings-btton', color='primary', className='text-center mb-2',
                       size='md')],
                      href=connect_withings_link(
                          NokiaAuth(config.get('withings', 'client_id'), config.get('withings', 'client_secret'),
                                    callback_uri=config.get('withings', 'redirect_uri'))))
    else:
        return html.H4('Withings Connected!', className='text-center col-lg-12', )
예제 #14
0
 def test_attributes(self):
     """ Make sure the NokiaAuth objects have the right attributes """
     assert hasattr(NokiaAuth, 'URL')
     self.assertEqual(NokiaAuth.URL, 'https://account.health.nokia.com')
     auth = NokiaAuth(*self.auth_args, callback_uri=self.callback_uri)
     assert hasattr(auth, 'client_id')
     self.assertEqual(auth.client_id, self.client_id)
     assert hasattr(auth, 'consumer_secret')
     self.assertEqual(auth.consumer_secret, self.consumer_secret)
     assert hasattr(auth, 'callback_uri')
     self.assertEqual(auth.callback_uri, self.callback_uri)
     assert hasattr(auth, 'scope')
     self.assertEqual(auth.scope, 'user.metrics')
예제 #15
0
 def __init__(self):
     try:
         with open('personal_dashboard/nokia_data.pkl',
                   'rb') as pickle_file:
             nokia = pickle.load(pickle_file)
             self.measures = nokia.get_measures()
             measures = nokia.get_measures(limit=1)
             self.weight = round(float(measures[0].weight) * 2.20462, 2)
             pickle_file.close()
     except:
         auth = NokiaAuth(WITHINGS_KEYS['API_KEY'],
                          WITHINGS_KEYS['API_SECRET'])
         authorize_url = auth.get_authorize_url()
         print("Go to %s allow the app and copy your oauth_verifier" %
               authorize_url)
         oauth_verifier = input('Please enter your oauth_verifier: ')
         creds = auth.get_credentials(oauth_verifier)
         client = NokiaApi(creds)
         with open('personal_dashboard/nokia_data.pkl', 'wb') as output:
             pickle.dump(client, output, pickle.HIGHEST_PROTOCOL)
         self.measures = client.get_measures()
         measures = client.get_measures(limit=1)
         #Convert Kg to Lbs
         self.weight = round(float(measures[0].weight) * 2.20462, 2)
예제 #16
0
    def __init__(self, smarthome, consumer_key, consumer_secret, access_token, access_token_secret, user_id, cycle=300):
        self.logger = logging.getLogger(__name__)
        self._sh = smarthome
        self._consumer_key = consumer_key
        self._consumer_secret = consumer_secret
        self._access_token = access_token
        self._access_token_secret = access_token_secret
        self._auth = NokiaAuth(self._consumer_key, self._consumer_secret)
        self._user_id = user_id
        self._creds = NokiaCredentials(self._access_token, self._access_token_secret, self._consumer_key,
                                       self._consumer_secret, self._user_id)
        self._client = NokiaApi(self._creds)

        self._cycle = cycle
        self._items = {}

        if not self.init_webinterface():
            self._init_complete = False
예제 #17
0
    def get(self, request):
        """Finish OAuth callback request."""
        from oauthlib.oauth2.rfc6749.errors import MismatchingStateError
        from oauthlib.oauth2.rfc6749.errors import MissingTokenError
        from nokia import NokiaAuth

        hass = request.app['hass']
        data = request.query

        response_message = """Nokia Health has been successfully authorized!
        You can close this window now!"""

        result = None
        if data.get('code') is not None:
            oauth = NokiaAuth(self.config.get(ATTR_API_KEY),
                              self.config.get(ATTR_API_SECRET))
            redirect_uri = oauth.get_authorize_url()

            try:
                result = self.oauth.fetch_access_token(data.get('code'),
                                                       redirect_uri)

                print(result)
                oauth_verifier = result.get('oauth_verifier')
                print(oauth_verifier)
            except MissingTokenError as error:
                _LOGGER.error("Missing token: %s", error)
                response_message = """Something went wrong when
                attempting authenticating with Nokia Health. The error
                encountered was {}. Please try again!""".format(error)
            except MismatchingStateError as error:
                _LOGGER.error("Mismatched state, CSRF error: %s", error)
                response_message = """Something went wrong when
                attempting authenticating with Nokia Health. The error
                encountered was {}. Please try again!""".format(error)
        else:
            _LOGGER.error("Unknown error when authing")
            response_message = """Something went wrong when
                attempting authenticating with Nokia Health.
                An unknown error occurred. Please try again!
                """

        if result is None:
            _LOGGER.error("Unknown error when authing")
            response_message = """Something went wrong when
                attempting authenticating with Nokia Health.
                An unknown error occurred. Please try again!
                """

        html_response = """<html><head><title>Nokia Health Auth</title></head>
        <body><h1>{}</h1></body></html>""".format(response_message)

        if result:
            config_contents = {
                ATTR_ACCESS_TOKEN: result.get('access_token'),
                ATTR_REFRESH_TOKEN: result.get('refresh_token'),
                ATTR_CLIENT_ID: self.oauth.client_id,
                ATTR_CLIENT_SECRET: self.oauth.client_secret,
                ATTR_LAST_SAVED_AT: int(time.time())
            }
        save_json(hass.config.path(NOKIA_HEALTH_CONFIG_FILE), config_contents)

        hass.async_add_job(setup_platform, hass, self.config, self.add_devices)

        return html_response
예제 #18
0
class WebInterface(SmartPluginWebIf):
    def __init__(self, webif_dir, plugin):
        """
        Initialization of instance of class WebInterface

        :param webif_dir: directory where the webinterface of the plugin resides
        :param plugin: instance of the plugin
        :type webif_dir: str
        :type plugin: object
        """
        self.logger = logging.getLogger(__name__)
        self.webif_dir = webif_dir
        self.plugin = plugin
        self._creds = None
        self._auth = None

        self.tplenv = self.init_template_environment()

    def _get_callback_url(self):
        ip = self.plugin.mod_http.get_local_ip_address()
        port = self.plugin.mod_http.get_local_port()
        web_ifs = self.plugin.mod_http.get_webifs_for_plugin(
            self.plugin.get_shortname())
        for web_if in web_ifs:
            if web_if['Instance'] == self.plugin.get_instance_name():
                callback_url = "http://{}:{}{}".format(ip, port,
                                                       web_if['Mount'])
                self.logger.debug(
                    "Plugin '{}': WebIf found, callback is {}".format(
                        self.plugin.get_fullname(), callback_url))
            return callback_url
        self.logger.error(
            "Plugin '{}': Callback URL cannot be established.".format(
                self.plugin.get_fullname()))

    @cherrypy.expose
    def index(self, reload=None, state=None, code=None, error=None):
        """
        Build index.html for cherrypy

        Render the template and return the html file to be delivered to the browser

        :return: contents of the template after beeing rendered
        """
        if self._auth is None:
            self._auth = NokiaAuth(
                self.plugin._client_id,
                self.plugin._consumer_secret,
                callback_uri=self._get_callback_url(),
                scope='user.info,user.metrics,user.activity')

        if not reload and code:
            self.logger.debug("Plugin '{}': Got code as callback: {}".format(
                self.plugin.get_fullname(), code))
            credentials = None
            try:
                credentials = self._auth.get_credentials(code)
            except Exception as e:
                self.logger.error(
                    "Plugin '{}': An error occurred, perhaps code parameter is invalid or too old? Message: {}"
                    .format(self.plugin.get_fullname(), str(e)))
            if credentials is not None:
                self._creds = credentials
                self.logger.debug(
                    "Plugin '{}': New credentials are: access_token {}, token_expiry {}, token_type {}, refresh_token {}"
                    .format(self.plugin.get_fullname(),
                            self._creds.access_token, self._creds.token_expiry,
                            self._creds.token_type, self._creds.refresh_token))
                self.plugin.get_item('access_token')(self._creds.access_token)
                self.plugin.get_item('token_expiry')(self._creds.token_expiry)
                self.plugin.get_item('token_type')(self._creds.token_type)
                self.plugin.get_item('refresh_token')(
                    self._creds.refresh_token)

                self.plugin._client = None

        tmpl = self.tplenv.get_template('index.html')
        return tmpl.render(plugin_shortname=self.plugin.get_shortname(),
                           plugin_version=self.plugin.get_version(),
                           interface=None,
                           item_count=len(self.plugin.get_items()),
                           plugin_info=self.plugin.get_info(),
                           tabcount=2,
                           callback_url=self._get_callback_url(),
                           tab1title="Withings Health Items (%s)" %
                           len(self.plugin.get_items()),
                           tab2title="OAuth2 Data",
                           authorize_url=self._auth.get_authorize_url(),
                           p=self.plugin,
                           token_expiry=datetime.datetime.fromtimestamp(
                               self.plugin.get_item('token_expiry')(),
                               tz=self.plugin.shtime.tzinfo()),
                           now=self.plugin.shtime.now(),
                           code=code,
                           state=state,
                           reload=reload,
                           language=self.plugin.get_sh().get_defaultlanguage())
예제 #19
0
    def index(self, reload=None, state=None, code=None, error=None):
        """
        Build index.html for cherrypy

        Render the template and return the html file to be delivered to the browser

        :return: contents of the template after beeing rendered
        """
        if self._auth is None:
            self._auth = NokiaAuth(
                self.plugin._client_id,
                self.plugin._consumer_secret,
                callback_uri=self._get_callback_url(),
                scope='user.info,user.metrics,user.activity')

        if not reload and code:
            self.logger.debug("Plugin '{}': Got code as callback: {}".format(
                self.plugin.get_fullname(), code))
            credentials = None
            try:
                credentials = self._auth.get_credentials(code)
            except Exception as e:
                self.logger.error(
                    "Plugin '{}': An error occurred, perhaps code parameter is invalid or too old? Message: {}"
                    .format(self.plugin.get_fullname(), str(e)))
            if credentials is not None:
                self._creds = credentials
                self.logger.debug(
                    "Plugin '{}': New credentials are: access_token {}, token_expiry {}, token_type {}, refresh_token {}"
                    .format(self.plugin.get_fullname(),
                            self._creds.access_token, self._creds.token_expiry,
                            self._creds.token_type, self._creds.refresh_token))
                self.plugin.get_item('access_token')(self._creds.access_token)
                self.plugin.get_item('token_expiry')(self._creds.token_expiry)
                self.plugin.get_item('token_type')(self._creds.token_type)
                self.plugin.get_item('refresh_token')(
                    self._creds.refresh_token)

                self.plugin._client = None

        tmpl = self.tplenv.get_template('index.html')
        return tmpl.render(plugin_shortname=self.plugin.get_shortname(),
                           plugin_version=self.plugin.get_version(),
                           interface=None,
                           item_count=len(self.plugin.get_items()),
                           plugin_info=self.plugin.get_info(),
                           tabcount=2,
                           callback_url=self._get_callback_url(),
                           tab1title="Withings Health Items (%s)" %
                           len(self.plugin.get_items()),
                           tab2title="OAuth2 Data",
                           authorize_url=self._auth.get_authorize_url(),
                           p=self.plugin,
                           token_expiry=datetime.datetime.fromtimestamp(
                               self.plugin.get_item('token_expiry')(),
                               tz=self.plugin.shtime.tzinfo()),
                           now=self.plugin.shtime.now(),
                           code=code,
                           state=state,
                           reload=reload,
                           language=self.plugin.get_sh().get_defaultlanguage())
예제 #20
0
파일: withings.py 프로젝트: ryant71/fitly
from oura import OuraOAuth2Client
from lib.withingsAPI import save_withings_token
import configparser
import re
import time

from nokia import NokiaAuth, NokiaApi

config = configparser.ConfigParser()
config.read('config.ini')

client_id = config.get('withings', 'client_id')
client_secret = config.get('withings', 'client_secret')
redirect_uri = config.get('withings', 'redirect_uri')

auth_client = NokiaAuth(client_id, client_secret, callback_uri=redirect_uri)

layout = html.Div(id='withings-auth-canvas',
                  children=[
                      html.Div(id='withings-token-refresh',
                               style={'display': 'none'}),
                      dcc.Loading(html.Div(id='withings-auth-layout'))
                  ])


def test_withings_connection():
    time.sleep(3)
    if not withings_connected():
        return html.Div(style={'textAlign': 'center'},
                        className='twelve columns',
                        children=[
예제 #21
0
파일: settings.py 프로젝트: snowind/fitly
from nokia import NokiaAuth, NokiaApi
from ..api.sqlalchemy_declarative import db_connect, stravaSummary, ouraSleepSummary, athlete, hrvWorkoutStepLog
from ..api.datapull import refresh_database
from sqlalchemy import delete
import pandas as pd
from dateutil.relativedelta import relativedelta
from datetime import datetime
import operator
from ..api.fitlyAPI import hrv_training_workflow
from ..app import app
from flask import current_app as server
import re
from ..utils import config

strava_auth_client = get_strava_client()
withings_auth_client = NokiaAuth(config.get('withings', 'client_id'), config.get('withings', 'client_secret'),
                                 callback_uri=config.get('withings', 'redirect_uri'))
oura_auth_client = OuraOAuth2Client(client_id=config.get('oura', 'client_id'),
                                    client_secret=config.get('oura', 'client_secret'))


def get_layout(**kwargs):
    return html.Div([
        html.Div(id='settings-layout'),
        html.Div(id='clear-log-dummy', style={'display': 'none'}),
        html.Div(id='token-dummy', style={'display': 'none'}),
        dbc.Modal(id="settings-modal", centered=True, autoFocus=True, fade=False, backdrop=True, size='sm',
                  is_open=True,
                  children=[
                      dbc.ModalHeader("Enter Admin Password"),
                      dbc.ModalBody(className='text-center', children=[
                          dcc.Input(id='settings-password', type='password', placeholder='Password', value='')]),
def async_setup_platform(hass, config, async_add_devices, discovery_info=None):
    """Authenticate to the Withings API."""
    from nokia import NokiaApi, NokiaAuth, NokiaCredentials

    hass.http.register_view(WithingsAuthCallbackView())

    client_id = config.get(CONF_CLIENT_ID)
    consumer_secret = config.get(CONF_CONSUMER_SECRET)

    config_path = hass.config.path(WITHINGS_CONFIG_PATH)

    @asyncio.coroutine
    def _read_config():
        if not os.path.isfile(config_path):
            return None
        with open(config_path, 'r') as auth_file:
            config = json.load(auth_file)
            if config.get('client_id') == client_id:
                return config

    @asyncio.coroutine
    def _write_config(creds):
        with open(config_path, 'w') as auth_file:
            json.dump(
                {
                    'client_id': client_id,
                    'access_token': creds.access_token,
                    'refresh_token': creds.refresh_token,
                    'token_type': creds.token_type,
                    'token_expiry': creds.token_expiry,
                    'user_id': creds.user_id,
                }, auth_file)

    @asyncio.coroutine
    def _add_device(creds):
        client = NokiaApi(creds)
        withings = WithingsSensor(hass, client)
        yield from withings.async_update()
        return async_add_devices([withings])

    config = yield from _read_config()
    if config is not None:
        creds = NokiaCredentials(client_id=client_id,
                                 consumer_secret=consumer_secret,
                                 access_token=config['access_token'],
                                 token_expiry=config['token_expiry'],
                                 token_type=config['token_type'],
                                 refresh_token=['refresh_token'],
                                 user_id=config['user_id'])
        yield from _add_device(creds)
    else:
        callback_uri = '{}{}'.format(hass.config.api.base_url,
                                     WithingsAuthCallbackView.url)
        auth = NokiaAuth(client_id,
                         consumer_secret,
                         callback_uri=callback_uri,
                         scope='user.info,user.metrics,user.activity')
        authorize_url = auth.get_authorize_url()

        configurator = hass.components.configurator
        request_id = configurator.async_request_config(
            "Withings",
            description="Authorization required for Withings account.",
            link_name="Authorize Home Assistant",
            link_url=authorize_url,
            entity_picture='/local/images/logo_nokia_health_mate.png')

    @asyncio.coroutine
    def initialize_callback(code):
        """Handle OAuth callback from Withings authorization flow."""
        creds = auth.get_credentials(code)
        yield from _write_config(creds)
        yield from _add_device(creds)
        configurator.async_request_done(request_id)

    hass.data[DATA_CALLBACK] = initialize_callback
    return True
def async_setup_platform(hass, config, async_add_devices, discovery_info=None):
    """Authenticate to the Nokia Health API."""
    from nokia import NokiaApi, NokiaAuth, NokiaCredentials

    hass.http.register_view(NokiaAuthCallbackView())

    consumer_key = config.get(CONF_CONSUMER_KEY)
    consumer_secret = config.get(CONF_CONSUMER_SECRET)

    config_path = hass.config.path(NOKIA_CONFIG_PATH)

    @asyncio.coroutine
    def _read_config():
        if not os.path.isfile(config_path):
            return None
        with open(config_path, 'r') as auth_file:
            config = json.load(auth_file)
            if config['consumer_key'] == consumer_key:
                return config

    @asyncio.coroutine
    def _write_config(creds):
        with open(config_path, 'w') as auth_file:
            json.dump(
                {
                    'consumer_key': consumer_key,
                    'access_token': creds.access_token,
                    'access_token_secret': creds.access_token_secret,
                    'user_id': creds.user_id,
                }, auth_file)

    @asyncio.coroutine
    def _add_device(creds):
        client = NokiaApi(creds)
        nokia = NokiaSensor(hass, client)
        yield from nokia.async_update()
        return async_add_devices([nokia])

    config = yield from _read_config()
    if config is not None:
        creds = NokiaCredentials(config['access_token'],
                                 config['access_token_secret'], consumer_key,
                                 consumer_secret, config['user_id'])
        yield from _add_device(creds)
    else:
        auth = NokiaAuth(consumer_key, consumer_secret)
        callback_uri = '{}{}'.format(hass.config.api.base_url,
                                     NokiaAuthCallbackView.url)
        authorize_url = auth.get_authorize_url(callback_uri=callback_uri)

        configurator = hass.components.configurator
        request_id = configurator.async_request_config(
            "Nokia Health",
            description="Authorization required for Nokia Health account.",
            link_name="Authorize Home Assistant",
            link_url=authorize_url,
            entity_picture='/local/images/logo_nokia_health_mate.png')

    @asyncio.coroutine
    def initialize_callback(oauth_verifier):
        """Handle OAuth callback from Nokia authorization flow."""
        creds = auth.get_credentials(oauth_verifier)
        yield from _write_config(creds)
        yield from _add_device(creds)
        configurator.async_request_done(request_id)

    hass.data[DATA_CALLBACK] = initialize_callback
    return True