From e663988c10709c13a118a6c4cda8ee55782010e7 Mon Sep 17 00:00:00 2001 From: Feanil Patel Date: Wed, 9 Aug 2023 12:00:18 -0400 Subject: [PATCH 01/10] docs: Add some basic docs on the Rest API. There is probably a lot more to say but add a quick How-To and concept docs that we can build on. --- docs/concepts/index.rst | 1 + docs/concepts/rest_apis.rst | 32 ++++++++++++++ docs/how-tos/use_the_api.rst | 86 ++++++++++++++++++++++++++++++++++++ docs/references/lms_apis.rst | 4 ++ 4 files changed, 123 insertions(+) create mode 100644 docs/concepts/rest_apis.rst create mode 100644 docs/how-tos/use_the_api.rst diff --git a/docs/concepts/index.rst b/docs/concepts/index.rst index 01f9250379..fa4a02125f 100644 --- a/docs/concepts/index.rst +++ b/docs/concepts/index.rst @@ -10,3 +10,4 @@ Concepts and Guides frontend/styling frontend/bootstrap frontend/static_assets + rest_apis diff --git a/docs/concepts/rest_apis.rst b/docs/concepts/rest_apis.rst new file mode 100644 index 0000000000..37c8390e60 --- /dev/null +++ b/docs/concepts/rest_apis.rst @@ -0,0 +1,32 @@ +edx-platform REST API Concepts +############################## + +APIs in the edx-platform fall into one of two categories. **Personal APIs** +that only let you manipluate resources related to your user (the single user +associated with the OAuth2 Application) or **Machine-to-machine APIs** that +allow 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)that allow 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` + * `OAuth2, JWT and Mobile `_ diff --git a/docs/how-tos/use_the_api.rst b/docs/how-tos/use_the_api.rst new file mode 100644 index 0000000000..c887911f20 --- /dev/null +++ b/docs/how-tos/use_the_api.rst @@ -0,0 +1,86 @@ +How To Use the REST API +####################### + +.. How-tos should have a short introduction sentence that captures the user's goal and introduces the steps. + +This how-to will help get setup to be able to make aunthenticated requests to +the edx-platform REST API. + +Assumptions +*********** + +.. This section should contain a bulleted list of assumptions you have of the + person who is following the How-to. The assumptions may link to other + how-tos if possible. + +* You have access to the edx-platform Django Admin (``/admin``) Panel. + +* You have a user that you want to make the rest calls as (``UserA``). + +* You are familiar with `the basics of HTTP and Rest`_ + +* For the purposes of this tutorial we'll assume your LMS is located at + https://lms.example.com + +.. _the basics of HTTP and Rest: https://code.tutsplus.com/a-beginners-guide-to-http-and-rest--net-16340t + +Steps +***** + +.. A task should have 3 - 7 steps. Tasks with more should be broken down into digestible chunks. + +#. Go to https://lms.example.com/admin/oauth2_provider/application/ + +#. Click :guilabel:`Add Application` + +#. Choose "UserA" for the user. + +#. Choose ``Confidential`` Client Type + +#. Choose "Client Credentials" for the Authorization Grant Type + +#. Set a name for your application. + +#. Save the ``client_id`` and ``client_secret``. + +#. The best way to interact with the edx-platform REST API is by making + requests using the JWT Authorization header. User the ``client_id`` and + ``client_secret`` to get a JWT token. + + .. code-block:: python + + import base64 + import requests + + client_id = "vovj0AItd9EnrOKjkDli0HpSF9HoooaTY9yueafn" + client_secret = "a3Fkwr24dfDSlIXt3v3q4Ob41CYQNZyGmtK8Y8ax0srpIa2vJON3OC5Rvj1i1wizsIUv1W1qM1Q2XPeuyjucNixsHXZsuw1dn2B9nH3IyjSvuFb5KoydDvWX8Hx8znqD" + + 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 + ) + access_token = token_request.json()["access_token"] + + +#. The code above will produce a JWT token that you can use to hit any existing + edx-platform API endpoint. + + .. code-block:: python + :name: Example, get all courses you're enrolled in. + :caption: Example, get all of UserA's Enrollments + + + enrollment_request = requests.get( + "http://localhost:8000/api/enrollment/v1/enrollment", + headers={"Authorization": f"JWT {access_token}"}, + ) + + +.. seealso:: + + * :doc:`/concepts/rest_apis` diff --git a/docs/references/lms_apis.rst b/docs/references/lms_apis.rst index 7c77b47e50..3776da77a3 100644 --- a/docs/references/lms_apis.rst +++ b/docs/references/lms_apis.rst @@ -3,5 +3,9 @@ LMS APIs The LMS currently has the following API Endpoints. +.. note:: + + Checkout :doc:`/how-tos/use_the_api` to learn how to authenticate against + these APIs .. openapi:: ../lms-openapi.yaml From 88096cc54d117e14f9287a75c38c14f97cf7aa92 Mon Sep 17 00:00:00 2001 From: Feanil Patel Date: Thu, 17 Aug 2023 10:18:47 -0400 Subject: [PATCH 02/10] docs: Add more examples related to Auth. --- docs/concepts/rest_apis.rst | 16 +-- docs/references/auth_code_samples.rst | 167 ++++++++++++++++++++++++++ docs/references/index.rst | 1 + 3 files changed, 176 insertions(+), 8 deletions(-) create mode 100644 docs/references/auth_code_samples.rst diff --git a/docs/concepts/rest_apis.rst b/docs/concepts/rest_apis.rst index 37c8390e60..2b381f648e 100644 --- a/docs/concepts/rest_apis.rst +++ b/docs/concepts/rest_apis.rst @@ -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 `_ + + * `Open edX Rest API Conventions ` + + diff --git a/docs/references/auth_code_samples.rst b/docs/references/auth_code_samples.rst new file mode 100644 index 0000000000..eb2ed61d2c --- /dev/null +++ b/docs/references/auth_code_samples.rst @@ -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'}] diff --git a/docs/references/index.rst b/docs/references/index.rst index d1a1af3986..bdafc21688 100644 --- a/docs/references/index.rst +++ b/docs/references/index.rst @@ -4,6 +4,7 @@ References .. toctree:: :maxdepth: 1 :glob: + :caption: Table of Contents * docstrings/index From 3e1a4ed311a0fa95bd499d2c4ca83aa2eb4b1e0f Mon Sep 17 00:00:00 2001 From: Feanil Patel Date: Thu, 17 Aug 2023 10:44:27 -0400 Subject: [PATCH 03/10] fixup! docs: Add some basic docs on the Rest API. --- docs/how-tos/use_the_api.rst | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/docs/how-tos/use_the_api.rst b/docs/how-tos/use_the_api.rst index c887911f20..e36eb7ec21 100644 --- a/docs/how-tos/use_the_api.rst +++ b/docs/how-tos/use_the_api.rst @@ -53,6 +53,8 @@ Steps import requests client_id = "vovj0AItd9EnrOKjkDli0HpSF9HoooaTY9yueafn" + # Client secretes should not be exposed in your code, we put it here to + # make the example more clear. client_secret = "a3Fkwr24dfDSlIXt3v3q4Ob41CYQNZyGmtK8Y8ax0srpIa2vJON3OC5Rvj1i1wizsIUv1W1qM1Q2XPeuyjucNixsHXZsuw1dn2B9nH3IyjSvuFb5KoydDvWX8Hx8znqD" credential = f"{client_id}:{client_secret}" @@ -62,7 +64,7 @@ Steps data = {"grant_type": "client_credentials", "token_type": "jwt"} token_request = requests.post( - "http://localhost:8000/oauth2/access_token", headers=headers, data=data + "http://lms.example.com/oauth2/access_token", headers=headers, data=data ) access_token = token_request.json()["access_token"] @@ -76,7 +78,7 @@ Steps enrollment_request = requests.get( - "http://localhost:8000/api/enrollment/v1/enrollment", + "http://lms.example.com/api/enrollment/v1/enrollment", headers={"Authorization": f"JWT {access_token}"}, ) @@ -84,3 +86,5 @@ Steps .. seealso:: * :doc:`/concepts/rest_apis` + + * :doc:`/references/auth_code_samples` From 1db57b574fe15d568f93a006a724f64d3dbf7278 Mon Sep 17 00:00:00 2001 From: Feanil Patel Date: Thu, 17 Aug 2023 10:44:39 -0400 Subject: [PATCH 04/10] fixup! docs: Add more examples related to Auth. --- docs/references/auth_code_samples.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/references/auth_code_samples.rst b/docs/references/auth_code_samples.rst index eb2ed61d2c..353d9b14b6 100644 --- a/docs/references/auth_code_samples.rst +++ b/docs/references/auth_code_samples.rst @@ -17,7 +17,7 @@ Get a JWT with a Username and Password from pprint import pprint token_request = requests.post( - f"http://localhost:8000/oauth2/access_token", + f"http://lms.example.com/oauth2/access_token", data={ "client_id": "login-service-client-id", "grant_type": "password", @@ -62,7 +62,7 @@ Get a JWT with a client_id and client_secret data = {"grant_type": "client_credentials", "token_type": "jwt"} token_request = requests.post( - "http://localhost:8000/oauth2/access_token", headers=headers, data=data + "http://lms.example.com/oauth2/access_token", headers=headers, data=data ) pprint(token_request.json()) @@ -105,7 +105,7 @@ Refresh a JWT Using a Refresh Token refresh_token = token_request.json()['refresh_token'] refreshed_token_request = requests.post( - f"http://localhost:8000/oauth2/access_token", + f"http://lms.example.com/oauth2/access_token", data={ "client_id": "login-service-client-id", "grant_type": "refresh_token", @@ -135,7 +135,7 @@ Use a JWT Header to call an API access_token = token_request.json()["access_token"] enrollment_request = requests.get( - "http://localhost:8000/api/enrollment/v1/enrollment", + "http://lms.example.com/api/enrollment/v1/enrollment", headers={"Authorization": f"JWT {access_token}"}, ) From 5a1abcb64fdaec5734d960dd0e440c0bb2a6993d Mon Sep 17 00:00:00 2001 From: Feanil Patel Date: Thu, 17 Aug 2023 10:47:56 -0400 Subject: [PATCH 05/10] fixup! docs: Add some basic docs on the Rest API. --- docs/concepts/rest_apis.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/concepts/rest_apis.rst b/docs/concepts/rest_apis.rst index 2b381f648e..ef1dfca031 100644 --- a/docs/concepts/rest_apis.rst +++ b/docs/concepts/rest_apis.rst @@ -29,4 +29,4 @@ one before you can call the API again. * `Open edX Rest API Conventions ` - + * `edX Enterprise REST API Auth Guide ` From df5759ca37b8da27ee42bc01f29852912d65424d Mon Sep 17 00:00:00 2001 From: Feanil Patel Date: Thu, 17 Aug 2023 11:11:59 -0400 Subject: [PATCH 06/10] docs: Make the docs easier to read and and some links. --- docs/concepts/rest_apis.rst | 35 ++++++++++++++++----------- docs/references/auth_code_samples.rst | 4 +++ 2 files changed, 25 insertions(+), 14 deletions(-) diff --git a/docs/concepts/rest_apis.rst b/docs/concepts/rest_apis.rst index ef1dfca031..69164d74c7 100644 --- a/docs/concepts/rest_apis.rst +++ b/docs/concepts/rest_apis.rst @@ -1,23 +1,30 @@ edx-platform REST API Concepts ############################## -APIs in the edx-platform fall into one of two categories. **Personal APIs** -that only let you manipluate resources related to your user (the single user -associated with the OAuth2 Application) or **Machine-to-machine APIs** that -allow you to manipulate other users and system resources so long as the user -associated with the OAuth2 application has the permissions to do so. +APIs in the edx-platform fall into one of two categories. + +#. **Personal APIs** that only let you manipluate resources related to your + user (the single user associated with the OAuth2 Application) + +#. **Machine-to-machine APIs** that allow 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) 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. +You can get a JWT one of two ways: -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. +#. Exchange the username and password for a user to get their JWT (see + :ref:`JWT from user`) + +#. Get a JWT associated with an 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. (see :ref:`JWT from application`) + +.. note:: 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:: @@ -27,6 +34,6 @@ one before you can call the API again. * `OAuth2, JWT and Mobile `_ - * `Open edX Rest API Conventions ` + * `Open edX Rest API Conventions `_ - * `edX Enterprise REST API Auth Guide ` + * `edX Enterprise REST API Auth Guide `_ diff --git a/docs/references/auth_code_samples.rst b/docs/references/auth_code_samples.rst index 353d9b14b6..0bd5980fb3 100644 --- a/docs/references/auth_code_samples.rst +++ b/docs/references/auth_code_samples.rst @@ -8,6 +8,8 @@ Authentication Related Code Samples examples are useful but you should generally not expose any of these tokens to systems or clients you don't trust. +.. _JWT from user: + Get a JWT with a Username and Password ************************************** @@ -39,6 +41,8 @@ Get a JWT with a Username and Password .. note:: The client type must be ``public`` for this to work. +.. _JWT from application: + Get a JWT with a client_id and client_secret ******************************************** From 73001b1a593e95a03f196086b676b58e59dafa53 Mon Sep 17 00:00:00 2001 From: Feanil Patel Date: Fri, 18 Aug 2023 10:14:02 -0400 Subject: [PATCH 07/10] docs: Apply suggestions from code review Typos and other small fixes. Co-authored-by: Robert Raposa --- docs/how-tos/use_the_api.rst | 6 +++--- docs/references/auth_code_samples.rst | 3 +-- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/docs/how-tos/use_the_api.rst b/docs/how-tos/use_the_api.rst index e36eb7ec21..0f680dc840 100644 --- a/docs/how-tos/use_the_api.rst +++ b/docs/how-tos/use_the_api.rst @@ -3,7 +3,7 @@ How To Use the REST API .. How-tos should have a short introduction sentence that captures the user's goal and introduces the steps. -This how-to will help get setup to be able to make aunthenticated requests to +This how-to will help you get setup to be able to make authenticated requests to the edx-platform REST API. Assumptions @@ -44,7 +44,7 @@ Steps #. Save the ``client_id`` and ``client_secret``. #. The best way to interact with the edx-platform REST API is by making - requests using the JWT Authorization header. User the ``client_id`` and + requests using the JWT Authorization header. Use the ``client_id`` and ``client_secret`` to get a JWT token. .. code-block:: python @@ -53,7 +53,7 @@ Steps import requests client_id = "vovj0AItd9EnrOKjkDli0HpSF9HoooaTY9yueafn" - # Client secretes should not be exposed in your code, we put it here to + # Client secrets should not be exposed in your code, we put it here to # make the example more clear. client_secret = "a3Fkwr24dfDSlIXt3v3q4Ob41CYQNZyGmtK8Y8ax0srpIa2vJON3OC5Rvj1i1wizsIUv1W1qM1Q2XPeuyjucNixsHXZsuw1dn2B9nH3IyjSvuFb5KoydDvWX8Hx8znqD" diff --git a/docs/references/auth_code_samples.rst b/docs/references/auth_code_samples.rst index 0bd5980fb3..9ab829febe 100644 --- a/docs/references/auth_code_samples.rst +++ b/docs/references/auth_code_samples.rst @@ -54,14 +54,13 @@ Get a JWT with a client_id and client_secret from pprint import pprint client_id = "ukbclQB8aPh7hgsy8ifPXkPf7fRqgUq1w21f2YZa" - # Note this should actually be secert and probably not in your code but + # Note this should actually be secret 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"} From b111440b7f94dbeda90b58227cb11a9a80c2c244 Mon Sep 17 00:00:00 2001 From: Feanil Patel Date: Fri, 18 Aug 2023 11:02:47 -0400 Subject: [PATCH 08/10] docs: Clarify comment for getting a refresh token. --- docs/references/auth_code_samples.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/references/auth_code_samples.rst b/docs/references/auth_code_samples.rst index 9ab829febe..b834da57ce 100644 --- a/docs/references/auth_code_samples.rst +++ b/docs/references/auth_code_samples.rst @@ -105,6 +105,8 @@ Refresh a JWT Using a Refresh Token import requests # See above examples for how to get a JWT token with a refresh token + # "Get a JWT with a Username and Password" + # The reponse from that request will include a `refresh_token` refresh_token = token_request.json()['refresh_token'] refreshed_token_request = requests.post( From 02354eff10970f97ebbbafb5e3e2c17aa77c1ea8 Mon Sep 17 00:00:00 2001 From: Feanil Patel Date: Fri, 18 Aug 2023 14:21:27 -0400 Subject: [PATCH 09/10] docs: Apply suggestions from code review --- docs/references/auth_code_samples.rst | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/docs/references/auth_code_samples.rst b/docs/references/auth_code_samples.rst index b834da57ce..5f44e953d5 100644 --- a/docs/references/auth_code_samples.rst +++ b/docs/references/auth_code_samples.rst @@ -104,9 +104,8 @@ Refresh a JWT Using a Refresh Token import requests - # See above examples for how to get a JWT token with a refresh token - # "Get a JWT with a Username and Password" - # The reponse from that request will include a `refresh_token` + # See "Get a JWT with a Username and Password" for how to get a refresh token. + # The reponse from that request will include a `refresh_token` attribute. refresh_token = token_request.json()['refresh_token'] refreshed_token_request = requests.post( From b6fc5488c6d6dc37682e13b3cda2b400170e661d Mon Sep 17 00:00:00 2001 From: Feanil Patel Date: Fri, 18 Aug 2023 14:21:56 -0400 Subject: [PATCH 10/10] docs: Apply suggestions from code review --- docs/references/auth_code_samples.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/references/auth_code_samples.rst b/docs/references/auth_code_samples.rst index 5f44e953d5..98d89eb2b9 100644 --- a/docs/references/auth_code_samples.rst +++ b/docs/references/auth_code_samples.rst @@ -105,7 +105,7 @@ Refresh a JWT Using a Refresh Token import requests # See "Get a JWT with a Username and Password" for how to get a refresh token. - # The reponse from that request will include a `refresh_token` attribute. + # The response from that request will include a `refresh_token` attribute. refresh_token = token_request.json()['refresh_token'] refreshed_token_request = requests.post(