Implementation of OAuth2 Server for Django. Feel free to fork this repository and contribute.
Written for Django 1.9 :)
http://tools.ietf.org/html/rfc6749#section-4.1
Insert test data:
$ python oauth2server/manage.py loaddata test_credentials
$ python oauth2server/manage.py loaddata test_scopes
Run the development web server:
$ python oauth2server/manage.py runserver
And you can now go to this page in your web browser:
http://localhost:8000/web/authorize/?response_type=code&client_id=testclient&redirect_uri=https://www.example.com&state=somestate
You should see a screen like this:
Click yes, you will be redirected to the redirect_uri and the authorization code will be in the query string. For example:
https://www.example.com/?code=cd45169cf6575f76d789f55764cb751b4d08274d&state=somestate
You can use it to get access token:
http://tools.ietf.org/html/rfc6749#section-4.1.3
$ curl -u testclient:testpassword localhost:8080/api/v1/tokens/ -d 'grant_type=authorization_code&code=cd45169cf6575f76d789f55764cb751b4d08274d'
You should get a response like:
{
"id": 1,
"access_token": "00ccd40e-72ca-4e79-a4b6-67c95e2e3f1c",
"expires_in": 3600,
"token_type": "Bearer",
"scope": "foo bar qux",
"refresh_token": "6fd8d272-375a-4d8a-8d0f-43367dc8b791"
}
http://tools.ietf.org/html/rfc6749#section-4.2
Very similar to the authorization code but the token is returned in URL fragment.
Insert test data:
$ python oauth2server/manage.py loaddata test_credentials
$ python oauth2server/manage.py loaddata test_scopes
Run the development web server:
$ python oauth2server/manage.py runserver
And you can now go to this page in your web browser:
http://localhost:8080/web/authorize/?response_type=token&client_id=testclient&redirect_uri=https://www.example.com&state=somestate
You should see a screen like this:
Click yes, you will be redirected to the redirect_uri and the access token code will be in the URL fragment. For example:
https://www.example.com#access_token=66b80fb9d6630705bcea1c9be0df2a5f7f7a52bf&expires_in=3600&token_type=Bearer&state=somestate
http://tools.ietf.org/html/rfc6749#section-4.3
Insert test data:
$ python oauth2server/manage.py loaddata test_credentials
$ python oauth2server/manage.py loaddata test_scopes
Run the development web server:
$ python oauth2server/manage.py runserver
And you can now get a new access token:
$ curl -u testclient:testpassword localhost:8080/api/v1/tokens/ -d 'grant_type=password&username=testuser@example.com&password=testpassword'
You should get a response like:
{
"id": 1,
"access_token": "00ccd40e-72ca-4e79-a4b6-67c95e2e3f1c",
"expires_in": 3600,
"token_type": "Bearer",
"scope": "foo bar qux",
"refresh_token": "6fd8d272-375a-4d8a-8d0f-43367dc8b791"
}
http://tools.ietf.org/html/rfc6749#section-4.4
Insert test data:
$ python oauth2server/manage.py loaddata test_credentials
$ python oauth2server/manage.py loaddata test_scopes
Run the development web server:
$ python oauth2server/manage.py runserver
And you can now get token either using HTTP Basic Authentication:
$ curl -u testclient:testpassword localhost:8080/api/v1/tokens/ -d 'grant_type=client_credentials'
Or using POST body:
$ curl localhost:8000/api/v1/tokens/ -d 'grant_type=client_credentials&client_id=testclient&client_secret=testpassword'
You should get a response like:
{
"id": 1,
"access_token": "00ccd40e-72ca-4e79-a4b6-67c95e2e3f1c",
"expires_in": 3600,
"token_type": "Bearer",
"scope": "foo bar qux",
"refresh_token": "6fd8d272-375a-4d8a-8d0f-43367dc8b791"
}
Let's say you have created a new access token using the user credentials grant type. The response included a refresh token which you can use to get a new access token before your current access token expires.
$ curl -u testclient:testpassword localhost:8080/api/v1/tokens/ -d 'grant_type=refresh_token&refresh_token=55697efd4b74c980f2c638602556115bc14ca931'
And you get a new access token:
{
"id": 1,
"access_token": "00ccd40e-72ca-4e79-a4b6-67c95e2e3f1c",
"expires_in": 3600,
"token_type": "Bearer",
"scope": "foo bar qux",
"refresh_token": "6fd8d272-375a-4d8a-8d0f-43367dc8b791"
}
http://tools.ietf.org/html/rfc6749#section-3.3
Scope is quite arbitrary. Basically it is a space delimited case-sensitive string where each part defines a specific access range.
You can define your scopes and insert them into tokens_oauthscope table, is_default flag can be used to specify default scope.
Now that you have obtained an access token, you can make requests to protected resources.
In order to require authentication for a view, wrap it in the authentication_required decorator:
from apps.tokens.decorators import authentication_required
@authentication_required("some_scope")
def some_view(request, *args, **kwargs):
...
In order to contribute to this project, fork it and make a pull request. I will review and accept it.
All tests must be passing in order for the pull request to be accepted.
Clone the repository:
$ git clone https://github.com/RichardKnop/django-oauth2-server.git
Create a virtual environment and install requirements:
$ virtualenv venv
$ source venv/bin/activate
$ pip install -r requirements.txt
Create a local.py file and insert correct configuration details:
$ cp oauth2server/proj/settings/local.example.py oauth2server/proj/settings/local.py
$ nano cp oauth2server/proj/settings/local.py
Sync the database:
$ python oauth2server/manage.py syncdb
These are the current configuration options:
OAUTH2_SERVER = {
'ACCESS_TOKEN_LIFETIME': 3600,
'AUTH_CODE_LIFETIME': 3600,
'REFRESH_TOKEN_LIFETIME': 1209600,
'IGNORE_CLIENT_REQUESTED_SCOPE': False,
}
- ACCESS_TOKEN_LIFETIME: lifetime of an access token in seconds
- AUTH_CODE_LIFETIME: lifetime of an authorization code in seconds
- REFRESH_TOKEN_LIFETIME: lifetime of a refresh token in seconds
- IGNORE_CLIENT_REQUESTED_SCOPE: if true, client requested scope will be ignored
$ python oauth2server/manage.py test