{"id":37075308,"url":"https://github.com/oscarychen/django-rest-microservice","last_synced_at":"2026-01-14T08:51:38.831Z","repository":{"id":57421667,"uuid":"455929318","full_name":"oscarychen/django-rest-microservice","owner":"oscarychen","description":"Provides OAuth2.0 Code Grant w/ PKCE authentication flow with third-party IDP (AWS Cognito), microservices architecture with Django, and out-of-box auth operation REST APIs for working with SPA.","archived":true,"fork":false,"pushed_at":"2023-01-07T06:36:17.000Z","size":1012,"stargazers_count":10,"open_issues_count":0,"forks_count":1,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-09-16T07:46:56.630Z","etag":null,"topics":["aws-cognito","django","django-rest-framework","jwt","microservice","microservices","oauth2","pkce"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/oscarychen.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2022-02-05T16:55:50.000Z","updated_at":"2025-02-20T13:53:02.000Z","dependencies_parsed_at":"2023-02-06T14:15:53.092Z","dependency_job_id":null,"html_url":"https://github.com/oscarychen/django-rest-microservice","commit_stats":null,"previous_names":[],"tags_count":5,"template":false,"template_full_name":null,"purl":"pkg:github/oscarychen/django-rest-microservice","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/oscarychen%2Fdjango-rest-microservice","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/oscarychen%2Fdjango-rest-microservice/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/oscarychen%2Fdjango-rest-microservice/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/oscarychen%2Fdjango-rest-microservice/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/oscarychen","download_url":"https://codeload.github.com/oscarychen/django-rest-microservice/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/oscarychen%2Fdjango-rest-microservice/sbom","scorecard":{"id":713300,"data":{"date":"2025-08-11","repo":{"name":"github.com/oscarychen/django-rest-microservice","commit":"427aac68bd280064ebdb8f99f56bb103fe25564c"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":1.2,"checks":[{"name":"Code-Review","score":0,"reason":"Found 1/11 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Dangerous-Workflow","score":-1,"reason":"no workflows found","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Token-Permissions","score":-1,"reason":"No tokens found","details":null,"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Maintained","score":0,"reason":"project is archived","details":["Warn: Repository is archived."],"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Pinned-Dependencies","score":0,"reason":"dependency not pinned by hash detected -- score normalized to 0","details":["Warn: pipCommand not pinned by hash: env_setup.sh:26","Warn: pipCommand not pinned by hash: env_setup.sh:27","Info:   0 out of   2 pipCommand dependencies pinned"],"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"License","score":0,"reason":"license file not detected","details":["Warn: project does not have a license file"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'master'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 1 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}},{"name":"Vulnerabilities","score":0,"reason":"36 existing vulnerabilities detected","details":["Warn: Project is vulnerable to: PYSEC-2022-190 / GHSA-2gwj-7jmv-h26r","Warn: Project is vulnerable to: PYSEC-2020-32 / GHSA-2m34-jcjv-45xf","Warn: Project is vulnerable to: PYSEC-2020-36 / GHSA-3gh2-xw74-jmcw","Warn: Project is vulnerable to: PYSEC-2022-1 / GHSA-53qw-q765-4fww","Warn: Project is vulnerable to: PYSEC-2021-98 / GHSA-68w8-qjq3-2gfm","Warn: Project is vulnerable to: GHSA-6c3j-c64m-qhgq","Warn: Project is vulnerable to: PYSEC-2019-10 / GHSA-6c7v-2f49-8h26","Warn: Project is vulnerable to: PYSEC-2022-20 / GHSA-6cw3-g6wv-c2xv","Warn: Project is vulnerable to: PYSEC-2019-13 / GHSA-6r97-cj55-9hrq","Warn: Project is vulnerable to: PYSEC-2019-79 / GHSA-7rp2-fm2h-wchj","Warn: Project is vulnerable to: GHSA-7xr5-9hcq-chf9","Warn: Project is vulnerable to: PYSEC-2022-2 / GHSA-8c5j-9r9f-c6w8","Warn: Project is vulnerable to: GHSA-8x94-hmjh-97hq","Warn: Project is vulnerable to: PYSEC-2022-19 / GHSA-95rw-fx8r-36v6","Warn: Project is vulnerable to: PYSEC-2019-11 / GHSA-c4qh-4vgv-qc6g","Warn: Project is vulnerable to: PYSEC-2020-34 / GHSA-fr28-569j-53c4","Warn: Project is vulnerable to: PYSEC-2021-9 / GHSA-fvgf-6h6h-3322","Warn: Project is vulnerable to: PYSEC-2019-12 / GHSA-h5jv-4p7w-64jg","Warn: Project is vulnerable to: PYSEC-2020-35 / GHSA-hmr4-m2h5-33qx","Warn: Project is vulnerable to: PYSEC-2019-15 / GHSA-hvmf-r92r-27hr","Warn: Project is vulnerable to: PYSEC-2022-3 / GHSA-jrh2-hc4r-7jwx","Warn: Project is vulnerable to: PYSEC-2020-33 / GHSA-m6gj-h9gm-gw44","Warn: Project is vulnerable to: PYSEC-2021-99 / GHSA-p99v-5w3c-jqq9","Warn: Project is vulnerable to: PYSEC-2021-8 / GHSA-qm57-vhq3-3fwf","Warn: Project is vulnerable to: GHSA-rrqc-c2jx-6jgv","Warn: Project is vulnerable to: PYSEC-2021-7 / GHSA-rxjp-mfm9-w4wr","Warn: Project is vulnerable to: PYSEC-2021-439 / GHSA-v6rh-hp5x-86rv","Warn: Project is vulnerable to: PYSEC-2019-14 / GHSA-v9qg-3j8p-r63v","Warn: Project is vulnerable to: PYSEC-2019-16 / GHSA-vfq6-hq5r-27r6","Warn: Project is vulnerable to: PYSEC-2022-191 / GHSA-w24h-v9qh-8gxj","Warn: Project is vulnerable to: PYSEC-2020-31 / GHSA-wpjr-j57x-wxfw","Warn: Project is vulnerable to: PYSEC-2021-6 / GHSA-xgxc-v2qg-chmh","Warn: Project is vulnerable to: PYSEC-2020-263 / GHSA-fx83-3ph3-9j2q","Warn: Project is vulnerable to: GHSA-gw84-84pc-xp82","Warn: Project is vulnerable to: GHSA-5vcc-86wm-547q","Warn: Project is vulnerable to: PYSEC-2022-43017 / GHSA-qwmp-2cf2-g9g6"],"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}}]},"last_synced_at":"2025-08-22T08:45:24.338Z","repository_id":57421667,"created_at":"2025-08-22T08:45:24.338Z","updated_at":"2025-08-22T08:45:24.338Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28414699,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-14T08:38:59.149Z","status":"ssl_error","status_checked_at":"2026-01-14T08:38:43.588Z","response_time":107,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["aws-cognito","django","django-rest-framework","jwt","microservice","microservices","oauth2","pkce"],"created_at":"2026-01-14T08:51:38.158Z","updated_at":"2026-01-14T08:51:38.808Z","avatar_url":"https://github.com/oscarychen.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# django-rest-microservice\n\nThis package is built on the \n[djangorestframework-simplejwt](https://github.com/jazzband/djangorestframework-simplejwt) package, which provides\nsome JWT authentication mechanisms with [Django REST framework](https://github.com/encode/django-rest-framework).\nThis package offers the following features:\n- Provides refresh cookie in HttpOnly cookie, and access token in response body, for better security \nwhen implemented properly with SPA.\n- Provides an easier approach to customizing token claims than the standard mechanism described in \ndjangorestframework-simplejwt documentation.\n- Provides a mechanism for authentication with a third-party IDP, before issuing internal JWT to your users.\n- Currently, supports authentication with AWS Cognito using OAuth 2 Code Grant with PKCE for best security practices.\n\nInstallation\n============\nInstall package to environment:\n```commandline\npip install django-rest-microservice\n```\nIn the main urls.py, include the default package url routes:\n```python\nfrom django.urls import path, include\n\nurlpatterns = [\n    path(\"auth/\", include(\"rest_framework_microservice.urls\"))\n]\n```\n\nIn Django settings, include the following:\n```python\n\nINSTALLED_APPS = [\n    ...,\n    'rest_framework_microservice',\n]\n\nREST_FRAMEWORK = {\n    'DEFAULT_AUTHENTICATION_CLASSES': (\n        'rest_framework_simplejwt.authentication.JWTTokenUserAuthentication',\n    )\n}\n```\n\nFor log off / token black listing feature to work, you also need to include the following in django settings:\n```python\nINSTALLED_APPS = [\n    ...,\n    'rest_framework_simplejwt.token_blacklist'\n]\n```\nand then run django migrations.\n\nREST API endpoints\n==================\n\n``{{domain}}/auth/sign-in/``\n-------------------------\nSign in directly against Django backend using username and password, retrieves access token and response body and \nrefresh token as HttpOnly cookie. The response body also contains a CSRF_token, which matches the same token set\nin the HttpOnly cookie.\n```commandline\ncurl --location --request POST '127.0.0.1:8000/auth/sign-in/' \\\n--header 'Content-Type: application/json' \\\n--data-raw '{\n    \"username\": \"admin\",\n    \"password\": \"admin\"\n}'\n```\n\n``{{domain}}/auth/social-exchange/``\n------------------------------------\nSubmits JWT tokens from an IDP (AWS Cognito), and in exchange for JWT tokens issue by Django server.\nThis will create a Django user if it does not already exist in the database. The response is the same as `sign-in`\nendpoint above.\n```commandline\ncurl --location --request POST '127.0.0.1:8000/auth/social-exchange/' \\\n--header 'Authorization: Bearer jwt_token_string \\\n--header 'Content-Type: application/json' \\\n--data-raw '{\n    \"id_token\": \"id_token_from_idp\",\n    \"access_token\": \"access_token_from_idp\",\n    \"refresh_token\": \"refresh_token_from_idp\",\n    \"expires_in\": 300,\n    \"token_type\": \"Bearer\"\n}'\n```\n\n``{{domain}}/auth/refresh/``\n----------------------------\nThis endpoint accepts the refresh token and csrf token in HttpOnly cookies, and return an access token in response body.\n```commandline\ncurl --location --request POST '127.0.0.1:8000/auth/refresh/' \\\n--header 'Authorization: Bearer jwt_token_string \\\n--header 'Content-Type: application/json' \\\n--data-raw '{\n    \"CSRF_token\": \"csrf_token\"\n}'\n```\n\n``{{domain}}/auth/logoff/``\n--------------------------\nThis endpoint requires `rest_framework_simplejwt.token_blacklist` to have been installed.\nCall this endpoint to blacklist the current refresh token.\n```commandline\ncurl --location --request POST '127.0.0.1:8000/auth/logoff/' \\\n--header 'Authorization: Bearer jwt_token_string \\\n--header 'Content-Type: application/json' \\\n--data-raw '{\n    \"CSRF_token\": \"csrf_token\"\n}'\n```\n\nSettings\n========\nSettings are specified in Django settings.py under `REST_FRAMEWORK_MICROSERVICE`, the defaults are\nthe following:\n```python\nREST_FRAMEWORK_MICROSERVICE = {\n    \"REFRESH_COOKIE_NAME\": \"refresh_cookie\",\n    \"REFRESH_COOKIE_PATH\": \"/auth\",\n    \"IDP\": {\n        \"PROVIDER\": \"aws\",\n        \"REGION\": \"us-west-2\",\n        \"USER_POOL\": \"us-west-2_abcdefg\",\n        \"CLIENT_ID\": \"abcdefg\",\n    },\n    \"CUSTOM_TOKEN_USER_ATTRIBUTES\": [],\n    \"CUSTOM_TOKEN_CALLABLE_ATTRIBUTES\": [],\n    \"COOKIE_SALT\": \"extra\",\n    \"USER_SERIALIZER_CLASS\": None,\n    \"USER_MODEL_UUID_FIELD\": None,\n}\n```\n\n``REFRESH_COOKIE_NAME``\n-----------------------\nName of refresh cookie to set in HTTP header.\n\n\n``REFRESH_COOKIE_PATH``\n-----------------------\nURL path of refresh cookie, this should be a string that starts with a slash, ie: \"/auth\". This path \nneeds to match the path of authentication endpoint path set in urls.py.\n\n\n``IDP``\n-----------------\nA dictionary containing IDP attributes:\n- ``PROVIDER``: a string identifying what IDP backend to use, defaults to `'aws'` \n(Currently only AWS Cognito is supported.)\n- ``REGION``: user pool region.\n- ``USER_POOL``: user pool identifier used with the IDP.\n- ``CLIENT_ID``: IDP client id for your application.\n\n\n\n``CUSTOM_TOKEN_USER_ATTRIBUTES``\n--------------------------------\n\nThe list of Django user attributes to be copied to token as claims. i.e.: ``['is_active',]``.\n\n``CUSTOM_TOKEN_CALLABLE_ATTRIBUTES``\n------------------------------------\n\nThis is used to customize claims which cannot be done by simply using ``CUSTOM_TOKEN_USER_ATTRIBUTES`` setting.\nThis should be a list of dictionaries containing ``attr_name`` and ``attr_getter``.\ni.e. : ``[{'attr_name': 'preferences', 'attr_getter': 'my_module.some_file.get_user_preferences'}, ...]``\n\nThe function specified in ``attr_getter`` should accept an argument of a Django user instance.\n\n``COOKIE_SALT``\n---------------\nSalt to be used when signing cookie.\n\n``USER_SERIALIZER_CLASS``\n-------------------------\nDefaults to None. If specified, the default view serializers will try to add a user object representing the user.\nThe content of the user object is defined by ``USER_SERIALIZER_CLASS``.\n\n``USER_MODEL_UUID_FIELD``\n-------------------------\nDefaults to None. Used to specify a field on the Django user model that can be used to store UUID from IDP.\n\n\nCustomizing token claims\n========================\n\nYou can include additional user attributes in the token claims by specifying them\nin the ``CUSTOM_TOKEN_USER_ATTRIBUTES``.\n\nYou can also specify functions to return the value for custom claims by using\n``CUSTOM_TOKEN_CALLABLE_ATTRIBUTES``.\n\n```python\n# settings.py\nREST_FRAMEWORK_MICROSERVICE = {\n  ...,\n  'CUSTOM_TOKEN_CALLABLE_ATTRIBUTES': [\n        {'attr_name': 'user_services',\n         'attr_getter': 'my_module.token_claims.get_user_subscribed_services'\n         }\n    ]\n}\n\n# my_module.token_claims.py\ndef get_user_subscribed_services(user):\n  return user.subscribed_services\n\n```\nIf you are using `djangorestframework-simplejwt` version \u003c= 5.0.0, you will also need to extend the \n`rest_framework_simplejwt.models.TokenUser` to include the additional claims. This is only applicable when using\n[older versions](https://github.com/jazzband/djangorestframework-simplejwt/pull/528/).\n\n```python\nfrom functools import cached_property\nfrom rest_framework_simplejwt.models import TokenUser\n\nclass CustomTokenUser(TokenUser):\n    \"\"\"\n    Extend TokenUser and adds custom attributes to be pulled from TokenUser.\n    This class should be specified in Django settings SIMPLE_JWT.TOKEN_USER_CLASS\n    \"\"\"\n\n    @cached_property\n    def first_name(self):\n        return self.token.get('first_name', None)\n```\nand include the following Django setting:\n```python\nSIMPLE_JWT = {\n    'TOKEN_USER_CLASS': 'microservice.models.CustomTokenUser'\n}\n```\n\nThird-party IDP\n===============\nThis package currently supports Cognito as an identity provider.\nYou can use AWS Cognito Userpool to enable social authentication.\nScreenshot below for an example of setting up Cognito with Google sign in.\n\n### AWS Cognito Userpool configurations\n![](docs/cognito_1.png)\n![](docs/cognito_2.png)\n![](docs/cognito_3.png)\n![](docs/cognito_4.png)\n![](docs/cognito_5.png)\n![](docs/cognito_6.png)\n![](docs/cognito_7.png)\n![](docs/cognito_8.png)\n### Google OAuth configurations\n![](docs/google_idp_1.png)\n![](docs/google_idp_2.png)\n![](docs/google_idp_3.png)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Foscarychen%2Fdjango-rest-microservice","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Foscarychen%2Fdjango-rest-microservice","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Foscarychen%2Fdjango-rest-microservice/lists"}