docs: Add more examples related to Auth.

This commit is contained in:
Feanil Patel
2023-08-17 10:18:47 -04:00
parent e663988c10
commit 88096cc54d
3 changed files with 176 additions and 8 deletions

View File

@@ -12,21 +12,21 @@ user and then pass that to the server as a part of the request header.
You can get a JWT one of two ways, one is to exchange the username and password
for a user to get their JWT, and the other is to get a JWT associated with an
OAuth2 Application (the application is associated with your user)that allow you
OAuth2 Application (the application is associated with your user) that allows you
to manipulate other users and system resources so long as the user associated
with the OAuth2 application has the permissions to do so.
The best way to interact with the APIs is to get a JWT Token associated with a
user and then pass that to the server as a part of the request header.
You can get a JWT one of two ways, one is to exchange the username and password
for a user to get their JWT, and the other is to get a JWT associated with an
OAuth2 Application (the application is associated with your user).
JWTs by default expire every hour so when they expire you'll have to get a new
one before you can call the API again.
.. seealso::
* :doc:`/how-tos/use_the_api`
* :doc:`/references/auth_code_samples`
* `OAuth2, JWT and Mobile <https://openedx.atlassian.net/wiki/spaces/AC/pages/42599769/OAuth2+JWT+and+Mobile>`_
* `Open edX Rest API Conventions <https://openedx.atlassian.net/wiki/spaces/AC/pages/18350757/Open+edX+REST+API+Conventions>`

View File

@@ -0,0 +1,167 @@
Authentication Related Code Samples
###################################
.. warning::
Access Tokens, Refresh Tokens and Client Secrets are generally considered
secret and should not live in your code. We print them here so that these
examples are useful but you should generally not expose any of these tokens
to systems or clients you don't trust.
Get a JWT with a Username and Password
**************************************
.. code-block::
import requests
from pprint import pprint
token_request = requests.post(
f"http://localhost:8000/oauth2/access_token",
data={
"client_id": "login-service-client-id",
"grant_type": "password",
"username": "test_user",
"password": "test_password",
"token_type": "JWT",
},
)
pprint(token_request.json())
.. code-block::
:caption: Output
{'access_token': 'eyJhbGciOiJIUzI1NiJ9.eyJhdWQiOiAibG1zLWtleSIsICJleHAiOiAxNjkyMjExNjM4LCAiZ3JhbnRfdHlwZSI6ICJwYXNzd29yZCIsICJpYXQiOiAxNjkyMjA4MDM4LCAiaXNzIjogImh0dHA6Ly9sb2NhbGhvc3Q6MTgwMDAvb2F1dGgyIiwgInByZWZlcnJlZF91c2VybmFtZSI6ICJmZWFuaWwiLCAic2NvcGVzIjogWyJyZWFkIiwgIndyaXRlIiwgImVtYWlsIiwgInByb2ZpbGUiXSwgInZlcnNpb24iOiAiMS4yLjAiLCAic3ViIjogIjVjMTBmNjZmMmQ2MzkwYjcwNjYyYzkxNGFhZTdlZjc5IiwgImZpbHRlcnMiOiBbInVzZXI6bWUiXSwgImlzX3Jlc3RyaWN0ZWQiOiBmYWxzZSwgImVtYWlsX3ZlcmlmaWVkIjogdHJ1ZSwgImVtYWlsIjogImZlYW5pbEBheGltLm9yZyIsICJuYW1lIjogIkZlYW5pbCBQYXRlbCIsICJmYW1pbHlfbmFtZSI6ICIiLCAiZ2l2ZW5fbmFtZSI6ICIiLCAiYWRtaW5pc3RyYXRvciI6IHRydWUsICJzdXBlcnVzZXIiOiB0cnVlfQ.iGFl7qsAUau0-40oq8Of0f72kguq2Hc_drijCnI2I-M',
'expires_in': 3600,
'refresh_token': 'm8iXhVlGABu52xFxVFj5rAz8xSjsRq',
'scope': 'read write email profile',
'token_type': 'JWT'}
.. note:: The client type must be ``public`` for this to work.
Get a JWT with a client_id and client_secret
********************************************
.. code-block::
import base64
import requests
from pprint import pprint
client_id = "ukbclQB8aPh7hgsy8ifPXkPf7fRqgUq1w21f2YZa"
# Note this should actually be secert and probably not in your code but
# provided here in the example
client_secret = "xkN0BJ19q9Jk8UPUppEtC1xe4764c81ioFtlegvokbmnAC7CFCT5gG1Og5nnFmCNc3NHNhUwWWDRVcBfnLSZ4xAlEmSePzfkFtLE06cwR1MuSc0gx9LUEjRrTs3j2vgK"
credential = f"{client_id}:{client_secret}"
encoded_credential = base64.b64encode(credential.encode("utf-8")).decode("utf-8")
headers = {"Authorization": f"Basic {encoded_credential}", "Cache-Control": "no-cache"}
data = {"grant_type": "client_credentials", "token_type": "jwt"}
token_request = requests.post(
"http://localhost:8000/oauth2/access_token", headers=headers, data=data
)
pprint(token_request.json())
.. code-block::
:caption: Output
{'access_token': 'eyJhbGciOiJIUzI1NiJ9.eyJhdWQiOiAibG1zLWtleSIsICJleHAiOiAxNjkyMjExNjM4LCAiZ3JhbnRfdHlwZSI6ICJjbGllbnQtY3JlZGVudGlhbHMiLCAiaWF0IjogMTY5MjIwODAzOCwgImlzcyI6ICJodHRwOi8vbG9jYWxob3N0OjE4MDAwL29hdXRoMiIsICJwcmVmZXJyZWRfdXNlcm5hbWUiOiAiZmVhbmlsIiwgInNjb3BlcyI6IFsicmVhZCIsICJ3cml0ZSIsICJlbWFpbCIsICJwcm9maWxlIl0sICJ2ZXJzaW9uIjogIjEuMi4wIiwgInN1YiI6ICI1YzEwZjY2ZjJkNjM5MGI3MDY2MmM5MTRhYWU3ZWY3OSIsICJmaWx0ZXJzIjogW10sICJpc19yZXN0cmljdGVkIjogZmFsc2UsICJlbWFpbF92ZXJpZmllZCI6IHRydWUsICJlbWFpbCI6ICJmZWFuaWxAYXhpbS5vcmciLCAibmFtZSI6ICJGZWFuaWwgUGF0ZWwiLCAiZmFtaWx5X25hbWUiOiAiIiwgImdpdmVuX25hbWUiOiAiIiwgImFkbWluaXN0cmF0b3IiOiB0cnVlLCAic3VwZXJ1c2VyIjogdHJ1ZX0.CX1S0QGrWKEPOHC8kUzGcvW8Ky04RCA8vU8WJrZURSw',
'expires_in': 3600,
'scope': 'read write email profile',
'token_type': 'JWT'}
.. note:: When you get a JWT using ``client_credentials`` you don't get a
refresh token. You're just expected to make a new call with your client
credentials.
Check to see if a JWT is Expired
********************************
.. code-block::
import jwt
# See above examples for how to get a JWT token
jwt_token = token_request.json()['access_token']
try:
jwt.decode(jwt_token, "secret", audience="lms-key", algorithms=['HS256'])
except jwt.ExpiredSignatureError:
# Signature has expired
Refresh a JWT Using a Refresh Token
***********************************
.. code-block::
import requests
# See above examples for how to get a JWT token with a refresh token
refresh_token = token_request.json()['refresh_token']
refreshed_token_request = requests.post(
f"http://localhost:8000/oauth2/access_token",
data={
"client_id": "login-service-client-id",
"grant_type": "refresh_token",
"refresh_token": token_request.json()['refresh_token'],
"token_type": "JWT",
},
)
pprint(refreshed_token_request.json())
.. code-block::
:caption: Output
{'access_token': 'eyJhbGciOiJIUzI1NiJ9.eyJhdWQiOiAibG1zLWtleSIsICJleHAiOiAxNjkyMjE1MTgwLCAiZ3JhbnRfdHlwZSI6ICJwYXNzd29yZCIsICJpYXQiOiAxNjkyMjExNTgwLCAiaXNzIjogImh0dHA6Ly9sb2NhbGhvc3Q6MTgwMDAvb2F1dGgyIiwgInByZWZlcnJlZF91c2VybmFtZSI6ICJmZWFuaWwiLCAic2NvcGVzIjogWyJyZWFkIiwgIndyaXRlIiwgImVtYWlsIiwgInByb2ZpbGUiXSwgInZlcnNpb24iOiAiMS4yLjAiLCAic3ViIjogIjVjMTBmNjZmMmQ2MzkwYjcwNjYyYzkxNGFhZTdlZjc5IiwgImZpbHRlcnMiOiBbInVzZXI6bWUiXSwgImlzX3Jlc3RyaWN0ZWQiOiBmYWxzZSwgImVtYWlsX3ZlcmlmaWVkIjogdHJ1ZSwgImVtYWlsIjogImZlYW5pbEBheGltLm9yZyIsICJuYW1lIjogIkZlYW5pbCBQYXRlbCIsICJmYW1pbHlfbmFtZSI6ICIiLCAiZ2l2ZW5fbmFtZSI6ICIiLCAiYWRtaW5pc3RyYXRvciI6IHRydWUsICJzdXBlcnVzZXIiOiB0cnVlfQ.oNTEk7aMFSjvEbvH_-Gu2QZE93w-CpXSIIuN-IC6BSU',
'expires_in': 3600,
'token_type': 'JWT',
'scope': 'read write email profile',
'refresh_token': 'V5fbgDt2RPVnmI6Q3c6cJ3OjVriGii'}
Use a JWT Header to call an API
*******************************
.. code-block::
# See above examples for how to get a JWT token
access_token = token_request.json()["access_token"]
enrollment_request = requests.get(
"http://localhost:8000/api/enrollment/v1/enrollment",
headers={"Authorization": f"JWT {access_token}"},
)
pprint(enrollment_request.json())
.. code-block::
:caption: Output
[{'course_details': {'course_end': None,
'course_id': 'course-v1:TestX+Course+1',
'course_modes': [{'bulk_sku': None,
'currency': 'usd',
'description': None,
'expiration_datetime': None,
'min_price': 0,
'name': 'Audit',
'sku': None,
'slug': 'audit',
'suggested_prices': ''}],
'course_name': 'Open edX Test Course',
'course_start': '2022-04-09T00:00:00Z',
'enrollment_end': None,
'enrollment_start': None,
'invite_only': False,
'pacing_type': 'Instructor Paced'},
'created': '2023-08-17T14:10:48.476967Z',
'is_active': True,
'mode': 'audit',
'user': 'test_user'}]

View File

@@ -4,6 +4,7 @@ References
.. toctree::
:maxdepth: 1
:glob:
:caption: Table of Contents
*
docstrings/index