docs: Add more examples related to Auth.
This commit is contained in:
@@ -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>`
|
||||
|
||||
|
||||
|
||||
167
docs/references/auth_code_samples.rst
Normal file
167
docs/references/auth_code_samples.rst
Normal 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'}]
|
||||
@@ -4,6 +4,7 @@ References
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
:glob:
|
||||
:caption: Table of Contents
|
||||
|
||||
*
|
||||
docstrings/index
|
||||
|
||||
Reference in New Issue
Block a user