Slide 1

Slide 1 text

Finally Understand User Authentication in Django REST Framework William Vincent DjangoCon US 2018 https://wsvincent.com

Slide 2

Slide 2 text

William Vincent

Slide 3

Slide 3 text

No content

Slide 4

Slide 4 text

wsvincent.com

Slide 5

Slide 5 text

/wsvincent

Slide 6

Slide 6 text

API Application Programming Interface

Slide 7

Slide 7 text

RESTful APIs ● Stateless ● Support HTTP methods ● URL endpoints ● Return JSON or XML

Slide 8

Slide 8 text

+

Slide 9

Slide 9 text

No content

Slide 10

Slide 10 text

No content

Slide 11

Slide 11 text

HTTP HyperText Transfer Protocol

Slide 12

Slide 12 text

HTTP Request/Response Cycle CLIENT SERVER

Slide 13

Slide 13 text

HTTP Verbs Functionality Create Read Update Delete HTTP Method/Verb POST GET PUT/PATCH DELETE Rough equivalence between CRUD & HTTP verbs

Slide 14

Slide 14 text

HTTP Status Codes Code 2xx 3xx 4xx 5xx Meaning Success (200, 201) Redirection (301) Client error (404, 401) Server error (500)

Slide 15

Slide 15 text

No content

Slide 16

Slide 16 text

No content

Slide 17

Slide 17 text

HTTP Anatomy 1) Start/Status line 2) Headers 3) Body (optional)

Slide 18

Slide 18 text

HTTP Request Start Line GET http://www.example.com HTTP/1.1 HTTP method URL HTTP version

Slide 19

Slide 19 text

HTTP Response Status Line HTTP/1.1 200 OK Status Code HTTP version

Slide 20

Slide 20 text

HTTP Anatomy 1) Start/Status line 2) Headers 3) Body (optional)

Slide 21

Slide 21 text

HTTP Request Message GET http://www.example.com HTTP/1.1 Host: www.example.com Start Line Header(s)

Slide 22

Slide 22 text

HTTP Response Message HTTP/1.1 200 OK Date: Wed, 03 Oct 2018 17:50:58 GMT Content-Type: text/html; charset=UTF-8 Content-Length: 1270 Start Line Header(s)

Slide 23

Slide 23 text

HTTP Anatomy 1) Start/Status line 2) Headers 3) Body (optional)

Slide 24

Slide 24 text

HTTP Request Message GET http://www.example.com HTTP/1.1 Host: www.example.com

Slide 25

Slide 25 text

HTTP Response Message HTTP/1.1 200 OK Date: Wed, 03 Oct 2018 17:50:58 GMT Content-Type: text/html; charset=UTF-8 Content-Length: 1270 Example Domain ...

Slide 26

Slide 26 text

Takeaway CLIENT SERVER GET http://www.example.com HTTP/1.1 HTTP/1.1 200 OK Host: www.example.com Date: Tue, 16 Oct 2018 22:38:34 GMT Content-Type: text/html; charset=UTF-8 Content-Length: 1270 Example Domain ...

Slide 27

Slide 27 text

REST API Endpoint

Slide 28

Slide 28 text

https://github.com/wsvincent/djangocon2018-rest-auth/

Slide 29

Slide 29 text

$ curl http://127.0.0.1:8000/users/ [{"id":1,"username":"wsv"}]

Slide 30

Slide 30 text

$ curl http://127.0.0.1:8000/users/ -v > GET /users/ HTTP/1.1 > Host: 127.0.0.1:8000 > < HTTP/1.1 200 OK < Date: Wed, 03 Oct 2018 16:37:28 GMT < Server: WSGIServer/0.2 CPython/3.7.0 < Vary: Accept, Cookie < Allow: GET, HEAD, OPTIONS < X-Frame-Options: SAMEORIGIN < [{“id”:1,”username”:”wsv”}]

Slide 31

Slide 31 text

No content

Slide 32

Slide 32 text

https://xkcd.com/1121/

Slide 33

Slide 33 text

HTTP Authentication CLIENT SERVER GET / HTTP/1.1 HTTP/1.1 401 Unauthorized WWW-Authenticate: Basic GET / HTTP/1.1 Authorization: Basic d3N2OnBhc3N3b3JkMTIz HTTP/1.1 200 OK

Slide 34

Slide 34 text

1. BasicAuthentication 2. SessionAuthentication 3. TokenAuthentication 4. RemoteUserAuthentication

Slide 35

Slide 35 text

#1 BasicAuthentication CLIENT SERVER 1) Send me web resource please? 2) Who are you? Identify yourself! 3) Hereʼs my username/password in Authorization HTTP Header. 4) Checks credentials. Looks good. Letʼs chat!

Slide 36

Slide 36 text

#1 BasicAuthentication CLIENT SERVER GET / HTTP/1.1 HTTP/1.1 401 Unauthorized WWW-Authenticate: Basic GET / HTTP/1.1 Authorization: Basic d3N2OnBhc3N3b3JkMTIz HTTP/1.1 200 OK

Slide 37

Slide 37 text

#1 BasicAuthentication (code) # settings.py REST_FRAMEWORK = { 'DEFAULT_AUTHENTICATION_CLASSES': [ 'rest_framework.authentication.BasicAuthentication', ] }

Slide 38

Slide 38 text

#1 BasicAuthentication Pros Cons Simple Every request look up Session Object Credentials passed in clear text Only suitable for testing Must use HTTPS

Slide 39

Slide 39 text

Cookies & Sessions

Slide 40

Slide 40 text

#2 SessionAuthentication CLIENT SERVER 1) Send me web resource please? 2) Who are you? Identify yourself! 3) Ok, Iʼll log in with credentials. 4) Looks good. Iʼve created a Session Object and ID. 5) Cool, Iʼll store the ID locally and include in HTTP Header. 6) Iʼll compare Session ID to Session Object on every request.

Slide 41

Slide 41 text

#2 SessionAuthentication (code) # settings.py REST_FRAMEWORK = { 'DEFAULT_AUTHENTICATION_CLASSES': [ 'rest_framework.authentication.SessionAuthentication', ] }

Slide 42

Slide 42 text

#2 SessionAuthentication Pros Cons Secure Not good for multiple front-ends Only validate user once Hard to keep up-to-date

Slide 43

Slide 43 text

#3 TokenAuthentication CLIENT SERVER 1) Send me web resource please? 2) Who are you? Identify yourself! 3) Ok, Iʼll log in with credentials. 4) Looks good. Iʼve created a signed Token. 5) Cool, Iʼll store the signed token and include in HTTP Header. 6) Iʼll check the signed token on every request.

Slide 44

Slide 44 text

#3 TokenAuthentication CLIENT SERVER GET / HTTP/1.1 HTTP/1.1 401 Unauthorized WWW-Authenticate: Token GET / HTTP/1.1 Authorization: Token 401f7ac837da42b97f613d789819ff93537bee6a HTTP/1.1 200 OK

Slide 45

Slide 45 text

#3 TokenAuthentication (code) # settings.py INSTALLED_APPS = [ 'rest_framework.authtoken', ] REST_FRAMEWORK = { 'DEFAULT_AUTHENTICATION_CLASSES': [ 'rest_framework.authentication.TokenAuthentication', ] }

Slide 46

Slide 46 text

#3 TokenAuthentication Pros Cons Easy to scale Large tokens hurt performance Only validate user once Tokens never expire

Slide 47

Slide 47 text

#4 RemoteUserAuthentication - Rarely used - Primarily for intranet sites (private networks)

Slide 48

Slide 48 text

BasicAuthentication - insecure, for testing only SessionAuthentication - same session context as website, powers DRF visualizer TokenAuthentication - secure, recommended default! RemoteUserAuthentication - intranet sites, rarely used

Slide 49

Slide 49 text

JSON Web Tokens

Slide 50

Slide 50 text

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ 9.eyJuYW1lIjoiV2lsbGlhbSBWaW5jZW50I iwibWVzc2FnZSI6IkhpIERqYW5nb0NvbiEi fQ.X5tcGt3N99t8HnjdLvPwDBDbgvU0WuqA S8MKX1Ao7RQ

Slide 51

Slide 51 text

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9 { 'alg': 'HS256', 'typ': 'JWT' }

Slide 52

Slide 52 text

eyJuYW1lIjoiV2lsbGlhbSBWaW5jZW50IiwibWVz c2FnZSI6IkhpIERqYW5nb0NvbiEifQ { "name": "William Vincent", "message": "Hi DjangoCon!" }

Slide 53

Slide 53 text

X5tcGt3N99t8HnjdLvPwDBDbgvU0WuqAS8MKX1Ao 7RQ

Slide 54

Slide 54 text

No content

Slide 55

Slide 55 text

JWTs (code) (env) $ pipenv install djangorestframework-simplejwt

Slide 56

Slide 56 text

JWTs (code) # settings.py REST_FRAMEWORK = { 'DEFAULT_AUTHENTICATION_CLASSES': [ 'rest_framework_simplejwt.authentication.JWTAuthentication', 'rest_framework.authentication.SessionAuthentication', ] }

Slide 57

Slide 57 text

JWTs Pros Cons Store more data Large size Can be signed Complicated setup Can be encrypted Can set to expire

Slide 58

Slide 58 text

https://github.com/wsvincent/drfx DRFx

Slide 59

Slide 59 text

Example Project

Slide 60

Slide 60 text

Getting Started $ pipenv install django $ pipenv shell (env) $ django-admin startproject example_project . (env) $ python manage.py startapp users

Slide 61

Slide 61 text

Custom User Model (part 1) # example_project/settings.py INSTALLED_APPS = [ ... # Local 'users.apps.UsersConfig', # new ] AUTH_USER_MODEL = 'users.CustomUser' # new

Slide 62

Slide 62 text

Custom User Model (part 2) # users/models.py from django.contrib.auth.models import AbstractUser from django.db import models class CustomUser(AbstractUser): pass

Slide 63

Slide 63 text

Custom User Model (part 3) # users/admin.py from django.contrib import admin from django.contrib.auth.admin import UserAdmin from .models import CustomUser class CustomUserAdmin(UserAdmin): model = CustomUser admin.site.register(CustomUser, CustomUserAdmin)

Slide 64

Slide 64 text

Custom User Model (part 4) (env) $ python manage.py makemigrations users (env) $ python manage.py migrate (env) $ python manage.py createsuperuser (env) $ python manage.py runserver

Slide 65

Slide 65 text

Install Django REST Framework (env) $ pipenv install djangorestframework

Slide 66

Slide 66 text

Install Django REST Framework # example_project/settings.py INSTALLED_APPS = [ ... # Local 'users.apps.UsersConfig', # 3rd party 'rest_framework', # new 'rest_framework.authtoken', # new ]

Slide 67

Slide 67 text

Add TokenAuthentication # example_project/settings.py REST_FRAMEWORK = { 'DEFAULT_AUTHENTICATION_CLASSES': [ 'rest_framework.authentication.SessionAuthentication', 'rest_framework.authentication.TokenAuthentication', ], }

Slide 68

Slide 68 text

Migrate new changes (env) $ python manage.py migrate

Slide 69

Slide 69 text

Install django-rest-auth (part 1) (env) $ pipenv install django-rest-auth

Slide 70

Slide 70 text

Install django-rest-auth (part 2) # example_project/settings.py INSTALLED_APPS = [ ... # Local 'users.apps.UsersConfig', # 3rd party 'rest_framework', 'rest_framework.authtoken', 'rest_auth', # new ]

Slide 71

Slide 71 text

Install django-rest-auth (part 3) # example_project/urls.py from django.contrib import admin from django.urls import path, include # new urlpatterns = [ path('admin/', admin.site.urls), path('rest-auth/', include('rest_auth.urls')), # new ]

Slide 72

Slide 72 text

http://127.0.0.1:8000/rest-auth/login/ http://127.0.0.1:8000/rest-auth/logout/

Slide 73

Slide 73 text

Install django-allauth (part 1) (env) $ pipenv install django-allauth

Slide 74

Slide 74 text

Install django-allauth (part 2) # example_project/settings.py INSTALLED_APPS = [ ... # Local 'users.apps.UsersConfig', # 3rd party 'rest_framework', 'rest_auth', 'django.contrib.sites', # new 'allauth', # new 'allauth.account', # new 'rest_auth.registration', # new ]

Slide 75

Slide 75 text

Install django-allauth (part 3) # example_project/settings.py EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend' # new SITE_ID = 1 # new

Slide 76

Slide 76 text

Install django-allauth (part 4) # example_project/urls.py from django.contrib import admin from django.urls import path, include urlpatterns = [ path('admin/', admin.site.urls), path('users/', include('users.urls')), path('rest-auth/', include('rest_auth.urls')), path('rest-auth/registration/', include('rest_auth.registration.urls')), # new ]

Slide 77

Slide 77 text

Install django-allauth (part 5) (env) $ python manage.py migrate (env) $ python manage.py runserver http://127.0.0.1:8000/rest-auth/registration/

Slide 78

Slide 78 text

Resources Source Code https://github.com/wsvincent/djangocon2018-rest-auth Slides https://tinyurl.com/djangocon2018-rest-auth My Site https://wsvincent.com