Repository: singingwolfboy/flask-dance

Issue:
The github.access_token return None even if the access token is available
A demonstration is in this app:
https://github.com/giocalitri/flask-dance-github/blob/gdm_test/github.py

After getting the token with the first endpoint, try to GET the second and you will have something like:

```
{
  "access_token": null, 
  "token": {
    "access_token": "XXXXXXXXXXXXXXXXXXXXXXXXXX", 
    "scope": [
      ""
    ], 
    "token_type": "bearer"
  }
}
```

Discussion:
codecov[bot]: # [Codecov](https://codecov.io/gh/singingwolfboy/flask-dance/pull/107?src=pr&el=h1) Report
> Merging [#107](https://codecov.io/gh/singingwolfboy/flask-dance/pull/107?src=pr&el=desc) into [master](https://codecov.io/gh/singingwolfboy/flask-dance/commit/588509a9ea35b9121680d7cccdafedc44d81b741?src=pr&el=desc) will **increase** coverage by `0.01%`.
> The diff coverage is `100%`.

[![Impacted file tree graph](https://codecov.io/gh/singingwolfboy/flask-dance/pull/107/graphs/tree.svg?height=150&width=650&src=pr&token=e0RPkq2h0p)](https://codecov.io/gh/singingwolfboy/flask-dance/pull/107?src=pr&el=tree)

```diff
@@            Coverage Diff             @@
##           master     #107      +/-   ##
==========================================
+ Coverage   95.92%   95.93%   +0.01%     
==========================================
  Files          21       21              
  Lines         711      713       +2     
==========================================
+ Hits          682      684       +2     
  Misses         29       29
```


| [Impacted Files](https://codecov.io/gh/singingwolfboy/flask-dance/pull/107?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [flask\_dance/consumer/requests.py](https://codecov.io/gh/singingwolfboy/flask-dance/pull/107/diff?src=pr&el=tree#diff-Zmxhc2tfZGFuY2UvY29uc3VtZXIvcmVxdWVzdHMucHk=) | `100% <100%> (ø)` | :arrow_up: |

------

[Continue to review full report at Codecov](https://codecov.io/gh/singingwolfboy/flask-dance/pull/107?src=pr&el=continue).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/singingwolfboy/flask-dance/pull/107?src=pr&el=footer). Last update [588509a...adad17d](https://codecov.io/gh/singingwolfboy/flask-dance/pull/107?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).


Patch:
diff --git a/CHANGELOG.rst b/CHANGELOG.rst
index 35a7a20..840bc74 100644
--- a/CHANGELOG.rst
+++ b/CHANGELOG.rst
@@ -3,7 +3,9 @@ Change Log
 
 unreleased
 ----------
-Nothing yet
+* Accessing the ``access_token`` property on an instance of the
+  ``OAuth2Session`` class will now query the token backend, instead of
+  checking the client on the instance.
 
 0.13.0 (2017-11-12)
 -------------------
diff --git a/flask_dance/consumer/requests.py b/flask_dance/consumer/requests.py
index 6c93abe..cd711a8 100644
--- a/flask_dance/consumer/requests.py
+++ b/flask_dance/consumer/requests.py
@@ -102,6 +102,10 @@ class OAuth2Session(BaseOAuth2Session):
             return True
         return False
 
+    @property
+    def access_token(self):
+        return self.token and self.token.get("access_token")
+
     @property
     def authorized(self):
         """ This is the property used when you have a statement in your code


Test patch:
diff --git a/tests/consumer/test_requests.py b/tests/consumer/test_requests.py
index 7cf3732..b071d1b 100644
--- a/tests/consumer/test_requests.py
+++ b/tests/consumer/test_requests.py
@@ -48,3 +48,27 @@ def test_oauth2session_not_authorized():
     bp = mock.Mock(token=None)
     sess = OAuth2Session(client_id="cid", blueprint=bp)
     assert sess.authorized == False
+
+
+def test_oauth2session_token():
+    bp = mock.Mock(token=FAKE_OAUTH2_TOKEN)
+    sess = OAuth2Session(client_id="cid", blueprint=bp)
+    assert sess.token == FAKE_OAUTH2_TOKEN
+
+
+def test_oauth2session_unset_token():
+    bp = mock.Mock(token=None)
+    sess = OAuth2Session(client_id="cid", blueprint=bp)
+    assert sess.token == None
+
+
+def test_oauth2session_access_token():
+    bp = mock.Mock(token=FAKE_OAUTH2_TOKEN)
+    sess = OAuth2Session(client_id="cid", blueprint=bp)
+    assert sess.access_token == "deadbeef"
+
+
+def test_oauth2session_unset_access_token():
+    bp = mock.Mock(token=None)
+    sess = OAuth2Session(client_id="cid", blueprint=bp)
+    assert sess.access_token == None