# -*- coding: utf-8 -*-
from setuptools import setup

packages = \
['oauth_login', 'oauth_login.migrations']

package_data = \
{'': ['*'], 'oauth_login': ['templates/oauth_login/*']}

setup_kwargs = {
    'name': 'django-oauth-login',
    'version': '0.1.0',
    'description': '',
    'long_description': '# django-oauth-login\n\n**Add OAuth login support to your Django project.**\n\nThis library is intentionally minimal.\nIt has no dependencies and a single database model.\nIf you simply want users to log in with GitHub, Google, Twitter, etc. (and maybe use that access token for API calls),\nthen this is the library for you.\n\nThere are three OAuth flows that it makes possible:\n\n1. Signup via OAuth (new user, new OAuth connection)\n2. Login via OAuth (existing user, existing OAuth connection)\n3. Connect/disconnect OAuth accounts to a user (existing user, new OAuth connection)\n\n\n## Usage\n\nInstall the package from PyPi:\n\n```sh\npip install django-oauth-login\n```\n\nAdd `oauth_login` to your `INSTALLED_APPS` in `settings.py`:\n\n```python\nINSTALLED_APPS = [\n    ...\n    "oauth_login",\n]\n```\n\nIn your `urls.py`, include `oauth_login.urls`:\n\n```python\nurlpatterns = [\n    path("oauth/", include("oauth_login.urls")),\n    ...\n]\n```\n\nCreate a new OAuth provider ([or copy one from our examples](provider_examples)):\n\n```python\n# yourapp/oauth.py\nimport requests\n\nfrom oauth_login.providers import OAuthProvider, OAuthToken, OAuthUser\n\n\nclass ExampleOAuthProvider(OAuthProvider):\n    authorization_url = "https://example.com/login/oauth/authorize"\n\n    def get_oauth_token(self, *, code, request):\n        response = requests.post(\n            "https://example.com/login/oauth/token",\n            headers={\n                "Accept": "application/json",\n            },\n            data={\n                "client_id": self.get_client_id(),\n                "client_secret": self.get_client_secret(),\n                "code": code,\n            },\n        )\n        response.raise_for_status()\n        data = response.json()\n        return OAuthToken(\n            access_token=data["access_token"],\n        )\n\n    def get_oauth_user(self, *, oauth_token):\n        response = requests.get(\n            "https://example.com/api/user",\n            headers={\n                "Accept": "application/json",\n                "Authorization": f"token {oauth_token.access_token}",\n            },\n        )\n        response.raise_for_status()\n        data = response.json()\n        return OAuthUser(\n            id=data["id"],\n            username=data["username"],\n            email=data["email"],\n        )\n```\n\nCreate your OAuth app/consumer on the provider\'s site (GitHub, Google, etc.).\nWhen setting it up, you\'ll likely need to give it a callback URL.\nIn development this can be `http://localhost:8000/oauth/github/callback/` (if you name it `"github"` like in the example below).\nAt the end you should get some sort of "client id" and "client secret" which you can then use in your `settings.py`:\n\n```python\nOAUTH_LOGIN_PROVIDERS = {\n    "github": {\n        "class": "yourapp.oauth.GitHubOAuthProvider",\n        "kwargs": {\n            "client_id": environ["GITHUB_CLIENT_ID"],\n            "client_secret": environ["GITHUB_CLIENT_SECRET"],\n            # "scope" is optional, defaults to ""\n\n            # You can add other fields if you have additional kwargs in your class __init__\n            # def __init__(self, *args, custom_arg="default", **kwargs):\n            #     self.custom_arg = custom_arg\n            #     super().__init__(*args, **kwargs)\n        },\n    },\n}\n```\n\nThen add a login button (which is a form using POST rather than a basic link, for security purposes):\n\n```html\n<h1>Login</h1>\n<form action="{% url \'oauth_login:login\' \'github\' %}" method="post">\n    {% csrf_token %}\n    <button type="submit">Login with GitHub</button>\n</form>\n```\n\nThat\'s pretty much it!\n\n## Advanced usage\n\n### Email addresses should be unique\n\nWhen you\'re integrating with an OAuth provider,\nwe think that the user\'s email address is the best "primary key" when linking to your `User` model in your app.\nUnfortunately in Django, by default an email address is not required to be unique!\n**We strongly recommend you require email addresses to be unique in your app.**\n\n[As suggested by the Django docs](https://docs.djangoproject.com/en/4.0/topics/auth/customizing/#using-a-custom-user-model-when-starting-a-project),\none way to do this is to have your own `User` model:\n\n```python\n# In an app named "users", for example\nfrom django.contrib.auth.models import AbstractUser\n\nclass User(AbstractUser):\n    email = models.EmailField(unique=True)\n\n\n# In settings.py\nAUTH_USER_MODEL = \'users.User\'\n```\n\nYou\'ll also notice that there are no "email confirmation" or "email verification" flows in this library.\nThis is also intentional.\nYou can implement something like that yourself if you need to,\nbut the easier solution in our opinion is to use an OAuth provider you *trust to have done that already*.\nIf you look at our [provider examples](provider_examples) you\'ll notice how we often use provider APIs to get the email address which is "primary" and "verified" already.\nIf they\'ve already done that work,\nthen we can just use that information.\n\n### Handling OAuth errors\n\nThe most common error you\'ll run into is if an existing user clicks a login button,\nbut they haven\'t yet connected that provider to their account.\nFor security reasons,\nthe required flow here is that the user actually logs in with another method (however they signed up) and then *connects* the OAuth provider from a settings page.\n\nFor this error (and a couple others),\nthere is an error template that is rendered.\nYou can customize this by copying `oauth_login/error.html` to one of your own template directories:\n\n```html\n{% extends "base.html" %}\n\n{% block content %}\n<h1>OAuth Error</h1>\n<p>{{ oauth_error }}</p>\n{% endblock %}\n```\n\n### Connecting and disconnecting OAuth accounts\n\n### Using a saved access token\n\n```python\nimport requests\n\n# Get the OAuth connection for a user\nconnection = user.oauth_connections.get(provider_key="github")\n\n# If the token can expire, check and refresh it\nif connection.access_token_expired():\n    connection.refresh_access_token()\n\n# Use the token in an API call\ntoken = connection.oauth_token\nresponse = requests.get(...)\n```\n\n### Using the Django system check\n\nThis library comes with a Django system check to ensure you don\'t *remove* a provider from `settings.py` that is still in use in your database.\n\n## FAQs\n\n### How is this different from [other Django OAuth libraries](https://djangopackages.org/grids/g/oauth/)?\n\nThe short answer is that *it does less*.\n\nIn [django-allauth](https://github.com/pennersr/django-allauth)\n(maybe the most popular alternative)\nyou get all kinds of other features like managing multiple email addresses,\nemail verification,\na long list of supported providers,\nand a whole suite of forms/urls/views/templates/signals/tags.\nAnd in my experience,\nit\'s too much.\nIt often adds more complexity to your app than you actually need (or want) and honestly it can just be a lot to wrap your head around.\nPersonally, I don\'t like the way that your OAuth settings are stored in the database vs when you use `settings.py`,\nand the implications for doing it one way or another.\n\nThe other popular OAuth libraries have similar issues,\nand I think their *weight* outweighs their usefulness for 80% of the use cases.\n\n### Why aren\'t providers included in the library itself?\n\nOne thing you\'ll notice is that we don\'t have a long list of pre-configured providers in this library.\nInstead, we have some examples (which you can usually just copy, paste, and use) and otherwise encourage you to wire up the provider yourself.\nOften times all this means is finding the two OAuth URLs ("oauth/authorize" and "oauth/token") in their docs,\nand writing two class methods that do the actual work of getting the user\'s data (which is often customized anyway).\n\nWe\'ve written examples for the following providers:\n\n- [GitHub](provider_examples/github.py)\n- [GitLab](provider_examples/gitlab.py)\n- [Bitbucket](provider_examples/bitbucket.py)\n\nJust copy that code and paste it in your project.\nTweak as necessary!\n\nThis might sound strange at first.\nBut in the long run we think it\'s actually *much* more maintainable for both us (as library authors) and you (as app author).\nIf something breaks with a provider, you can fix it immediately!\nYou don\'t need to try to run changes through us or wait for an upstream update.\nYou\'re welcome to contribute an example to this repo,\nand there won\'t be an expectation that it "works perfectly for every use case until the end of time".\n',
    'author': 'Dave Gaeddert',
    'author_email': 'dave.gaeddert@dropseed.dev',
    'maintainer': None,
    'maintainer_email': None,
    'url': 'https://github.com/dropseed/django-oauth-login',
    'packages': packages,
    'package_data': package_data,
    'python_requires': '>=3.8,<4.0',
}


setup(**setup_kwargs)
