Skip to content

Commit

Permalink
Fix doc errors
Browse files Browse the repository at this point in the history
  • Loading branch information
rayluo committed May 20, 2024
1 parent ee5717e commit 2c28b88
Show file tree
Hide file tree
Showing 7 changed files with 72 additions and 40 deletions.
26 changes: 14 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,9 +63,22 @@ By using this library, it will automatically renew signed-in session when the ID

* [Sample written in ![Django](https://raw.githubusercontent.com/rayluo/identity/dev/docs/django.webp)](https://github.com/Azure-Samples/ms-identity-python-webapp-django)
* [Sample written in ![Flask](https://raw.githubusercontent.com/rayluo/identity/dev/docs/flask.webp)](https://github.com/Azure-Samples/ms-identity-python-webapp)
* [Sample written in ![Quart](https://raw.githubusercontent.com/rayluo/identity/dev/docs/quart.webp)](https://github.com/rayluo/python-webapp-quart)
* Need support for more web frameworks?
[Upvote existing feature request or create a new one](https://github.com/rayluo/identity/issues)

</td>
</tr>

<tr>
<th>How to customize the login page</th>
<td colspan=4>

The default login page will typically redirect users to your Identity Provider,
so you don't have to customize it.
But if the default login page is shown in your browser,
you can read its HTML source code, and find the how-to instructions there.

</td>
</tr>

Expand All @@ -90,18 +103,6 @@ They are demonstrated by the same samples above.

In roadmap.

</td>
</tr>

<tr>
<th>How to customize the login page</th>
<td colspan=4>

The default login page will typically redirect users to your Identity Provider,
so you don't have to customize it.
But if the default login page is shown in your browser,
you can read its HTML source code, and find the how-to instructions there.

</td>
</tr>

Expand Down Expand Up @@ -134,6 +135,7 @@ Choose the package declaration that matches your web framework:

* Django: `pip install identity[django]`
* Flask: `pip install identity[flask]`
* Quart: `pip install identity[quart]`

## Versions

Expand Down
6 changes: 3 additions & 3 deletions docs/flask.rst
Original file line number Diff line number Diff line change
Expand Up @@ -73,19 +73,19 @@ Web app that logs in users and calls a web API on their behalf

#. Decorate your token-consuming views using the same
:py:func:`identity.flask.Auth.login_required` decorator,
this time with a parameter ``scopes=["your_scope_1", "your_scope_2"]``.
this time with a parameter ``scopes=["your_scope_1", "your_scope_2"]``.

Then, inside your view, the token will be readily available via
``context['access_token']``. For example::

@app.route("/call_api")
@auth.login_required(scopes=os.getenv("SCOPE", "").split())
@auth.login_required(scopes=["your_scope_1", "your_scope_2"])
def call_api(*, context):
api_result = requests.get( # Use access token to call a web api
"https://your_api.example.com",
headers={'Authorization': 'Bearer ' + context['access_token']},
timeout=30,
).json() # Here we assume the response format is json
)
...

All of the content above are demonstrated in
Expand Down
31 changes: 28 additions & 3 deletions docs/quart.rst
Original file line number Diff line number Diff line change
Expand Up @@ -35,20 +35,20 @@ Configuration


#. Setup session management with the `Quart-session <https://github.com/kroketio/quart-session>`_ package, which currently supports either Redis or MongoDB backing stores. To use Redis as the session store, you should first install the package with the extra dependency::

pip install quart-session[redis]

#. Then add configuration to ``app.py`` pointing to your Redis instance::

app.config['SESSION_TYPE'] = 'redis'
app.config['SESSION_URI'] = 'redis://localhost:6379'


Sign In and Sign Out
----------------------------------

#. In your web project's ``app.py``, decorate some views with the
:py:func:`identity.flask.Auth.login_required` decorator.
:py:func:`identity.quart.Auth.login_required` decorator.
It will automatically trigger sign-in. ::

@app.route("/")
Expand All @@ -63,6 +63,31 @@ Sign In and Sign Out
<a href="{{ url_for('identity.logout') }}">Logout</a>


Web app that logs in users and calls a web API on their behalf
--------------------------------------------------------------

#. Decorate your token-consuming views using the same
:py:func:`identity.quart.Auth.login_required` decorator,
this time with a parameter ``scopes=["your_scope_1", "your_scope_2"]``.

Then, inside your view, the token will be readily available via
``context['access_token']``. For example::

@app.route("/call_api")
@auth.login_required(scopes=["your_scope_1", "your_scope_2"])
async def call_api(*, context):
async with httpx.AsyncClient() as client:
api_result = await client.get( # Use access token to call a web api
os.getenv("ENDPOINT"),
headers={'Authorization': 'Bearer ' + context['access_token']},
)
return await render_template('display.html', result=api_result)


All of the content above are demonstrated in
`this Quart web app sample <https://github.com/rayluo/python-webapp-quart>`_.


API reference
--------------------------

Expand Down
Binary file added docs/quart.webp
Binary file not shown.
2 changes: 1 addition & 1 deletion identity/django.py
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ def my_view2(request, *, context):
"https://example.com/endpoint",
headers={'Authorization': 'Bearer ' + context['access_token']},
timeout=30,
).json() # Here we assume the response format is json
)
...
"""
# With or without brackets. Inspired by https://stackoverflow.com/a/39335652/728675
Expand Down
18 changes: 10 additions & 8 deletions identity/flask.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@ def __init__(self, app: Flask, *args, **kwargs):
# Manually register the routes, since we cannot use @app or @bp on methods
if self._redirect_uri:
redirect_path = urlparse(self._redirect_uri).path
#bp.route(redirect_path or "/auth_response")(self.auth_response)
bp.route(redirect_path)(self.auth_response)
bp.route(
f"{os.path.dirname(redirect_path)}/logout" # Use it in template by url_for("identity.logout")
Expand Down Expand Up @@ -107,12 +106,14 @@ def login_required( # Named after Django's login_required
Usage::
@settings.AUTH.login_required
def my_view(request, *, context):
return render(request, 'index.html', dict(
@app.route("/")
@auth.login_required
def index(*, context):
return render_template(
'index.html',
user=context["user"], # User is guaranteed to be present
# because we decorated this view with @login_required
))
)
:param list[str] scopes:
A list of scopes that your app will need to use.
Expand All @@ -121,13 +122,14 @@ def my_view(request, *, context):
Usage::
@settings.AUTH.login_required(scopes=["scope1", "scope2"])
def my_view2(request, *, context):
@app.route("/call_api")
@auth.login_required(scopes=["scope1", "scope2"])
def call_an_api(*, context):
api_result = requests.get( # Use access token to call an api
"https://example.com/endpoint",
headers={'Authorization': 'Bearer ' + context['access_token']},
timeout=30,
).json() # Here we assume the response format is json
)
...
"""
# With or without brackets. Inspired by https://stackoverflow.com/a/39335652/728675
Expand Down
29 changes: 16 additions & 13 deletions identity/quart.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@ def __init__(self, app: Quart, *args, **kwargs):
# Manually register the routes, since we cannot use @app or @bp on methods
if self._redirect_uri:
redirect_path = urlparse(self._redirect_uri).path
#bp.route(redirect_path or "/auth_response")(self.auth_response)
bp.route(redirect_path)(self.auth_response)
bp.route(
f"{os.path.dirname(redirect_path)}/logout" # Use it in template by url_for("identity.logout")
Expand Down Expand Up @@ -107,12 +106,14 @@ def login_required( # Named after Django's login_required
Usage::
@settings.AUTH.login_required
def my_view(request, *, context):
return render(request, 'index.html', dict(
@app.route("/")
@auth.login_required
async def index(*, context):
return await render_template(
'index.html',
user=context["user"], # User is guaranteed to be present
# because we decorated this view with @login_required
))
)
:param list[str] scopes:
A list of scopes that your app will need to use.
Expand All @@ -121,14 +122,16 @@ def my_view(request, *, context):
Usage::
@settings.AUTH.login_required(scopes=["scope1", "scope2"])
def my_view2(request, *, context):
api_result = requests.get( # Use access token to call an api
"https://example.com/endpoint",
headers={'Authorization': 'Bearer ' + context['access_token']},
timeout=30,
).json() # Here we assume the response format is json
...
@app.route("/call_api")
@auth.login_required(scopes=["scope1", "scope2"])
async def call_api(*, context):
async with httpx.AsyncClient() as client:
api_result = await client.get( # Use access token to call a web api
os.getenv("ENDPOINT"),
headers={'Authorization': 'Bearer ' + context['access_token']},
)
return await render_template('display.html', result=api_result)
"""
# With or without brackets. Inspired by https://stackoverflow.com/a/39335652/728675

Expand Down

0 comments on commit 2c28b88

Please sign in to comment.