├── LICENSE ├── MANIFEST.in ├── README.rst ├── firebase_auth ├── authentication.py ├── exceptions.py └── mixins.py └── setup.py /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Copyright (c) 2018, Felix Cornelius 3 | 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without modification, 7 | are permitted provided that the following conditions are met: 8 | 9 | * Redistributions of source code must retain the above copyright notice, 10 | this list of conditions and the following disclaimer. 11 | * Redistributions in binary form must reproduce the above copyright notice, 12 | this list of conditions and the following disclaimer in the documentation 13 | and/or other materials provided with the distribution. 14 | * Neither the name of django-firebase-auth nor the names of its contributors 15 | may be used to endorse or promote products derived from this software 16 | without specific prior written permission. 17 | 18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 22 | CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 23 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 24 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 25 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 26 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 27 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 28 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | 30 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include LICENSE 2 | include README.rst 3 | recursive-include firebase_auth * 4 | -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | ===== 2 | django-firebase-auth 3 | ===== 4 | 5 | django-firebase-auth is a authentication provider for Google's `Firebase Authentication Service `_ which blends right into django-rest-framework. 6 | Simply setup your Firebase keyfile location and mark views which need authentication with the FirebaseAuthMixin authentication class. 7 | 8 | 9 | Detailed documentation is in the "docs" directory. 10 | 11 | Installation 12 | ----------- 13 | 14 | Install via pip:: 15 | 16 | pip install django-firebase-auth 17 | 18 | (This will also install dependencies `django-rest-framework `_ and `firebase-admin `_.) 19 | 20 | Quick start 21 | ----------- 22 | 23 | 1. Add "firebase_auth" to your INSTALLED_APPS setting like this:: 24 | 25 | INSTALLED_APPS = [ 26 | ... 27 | 'firebase_auth', 28 | ] 29 | 30 | 2. Specify a location for your Firebase keyfile with the settings:: 31 | 32 | KEYFILES_DIR = os.path.join(BASE_DIR, 'keyfiles') 33 | FIREBASE_KEY = '.json' 34 | 35 | And place the json key inside BASE_DIR/keyfiles. 36 | 37 | 3. Either set FirebaseAuthentication as the global default authentication class in settings, like:: 38 | 39 | REST_FRAMEWORK = { 40 | 'DEFAULT_AUTHENTICATION_CLASSES': ('firebase_auth.authentication.FirebaseAuthentication', ), 41 | } 42 | 43 | Or extend specific views from FirebaseAuthMixin, like:: 44 | 45 | from firebase_auth import FirebaseAuthMixin 46 | class MyModelViewSet(FirebaseAuthMixin, viewsets.ModelViewSet) 47 | ... 48 | 49 | Note that the auth mixin has to be the first class extended by the view. 50 | 51 | 4. Create your users with the Firebase user ID as user ID. 52 | Inside your views, you can access the user reference like you're used to with request.user 53 | 54 | 55 | -------------------------------------------------------------------------------- /firebase_auth/authentication.py: -------------------------------------------------------------------------------- 1 | from rest_framework import authentication 2 | from django.contrib.auth.models import User 3 | from rest_framework import exceptions 4 | import firebase_admin 5 | from firebase_admin import credentials 6 | from firebase_admin import auth 7 | import os 8 | from django.conf import settings 9 | 10 | json = os.path.join(settings.KEYFILES_DIR, settings.FIREBASE_KEY) 11 | cred = credentials.Certificate(json) 12 | default_app = firebase_admin.initialize_app(cred) 13 | 14 | 15 | class FirebaseAuthentication(authentication.BaseAuthentication): 16 | def authenticate(self, request): 17 | id_token = request.META.get('HTTP_AUTHORIZATION') 18 | decoded_token = None 19 | try: 20 | decoded_token = auth.verify_id_token(id_token) 21 | except Exception as e: 22 | pass 23 | 24 | if not id_token or not decoded_token: 25 | return None 26 | 27 | uid = decoded_token.get('uid') 28 | try: 29 | user = User.objects.get(username=uid) 30 | except User.DoesNotExist: 31 | raise exceptions.AuthenticationFailed('The user does not exist') 32 | 33 | return (user, None) 34 | -------------------------------------------------------------------------------- /firebase_auth/exceptions.py: -------------------------------------------------------------------------------- 1 | from rest_framework import status 2 | from rest_framework.exceptions import APIException 3 | 4 | class NoAuthToken(APIException): 5 | status_code = status.HTTP_401_UNAUTHORIZED 6 | default_detail = 'No authentication token provided' 7 | default_code = 'no_auth_token' 8 | 9 | class InvalidAuthToken(APIException): 10 | status_code = status.HTTP_401_UNAUTHORIZED 11 | default_detail = 'Invalid authentication token provided' 12 | default_code = 'invalid_token' 13 | 14 | class FirebaseError(APIException): 15 | status_code = status.HTTP_500_INTERNAL_SERVER_ERROR 16 | default_detail = 'The user provided with the auth token is not a valid Firebase user, it has no Firebase UID' 17 | default_code = 'no_firebase_uid' 18 | 19 | -------------------------------------------------------------------------------- /firebase_auth/mixins.py: -------------------------------------------------------------------------------- 1 | from .authentication import FirebaseAuthentication 2 | from rest_framework.permissions import IsAuthenticated 3 | 4 | class FirebaseAuthMixin(): 5 | permission_classes = (IsAuthenticated,) 6 | authentication_classes = (FirebaseAuthentication,) 7 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | import os 2 | from setuptools import find_packages, setup 3 | 4 | with open(os.path.join(os.path.dirname(__file__), 'README.rst')) as readme: 5 | README = readme.read() 6 | 7 | # allow setup.py to be run from any path 8 | os.chdir(os.path.normpath(os.path.join(os.path.abspath(__file__), os.pardir))) 9 | 10 | setup( 11 | name='django-firebase-auth', 12 | version='0.4', 13 | packages=find_packages(), 14 | install_requires=[ 15 | 'firebase-admin', 16 | 'djangorestframework' 17 | ], 18 | include_package_data=True, 19 | license='BSD License', 20 | description='A django-rest-framework authentication provider for Google\'s Firebase Authentication Service', 21 | long_description=README, 22 | author='Felix Cornelius', 23 | author_email='mail@felixcornelius.de', 24 | classifiers=[ 25 | 'Environment :: Web Environment', 26 | 'Framework :: Django', 27 | 'Framework :: Django :: 1.11', 28 | 'Intended Audience :: Developers', 29 | 'License :: OSI Approved :: BSD License', 30 | 'Operating System :: OS Independent', 31 | 'Programming Language :: Python', 32 | 'Programming Language :: Python :: 3.5', 33 | 'Programming Language :: Python :: 3.6', 34 | 'Topic :: Internet :: WWW/HTTP', 35 | 'Topic :: Internet :: WWW/HTTP :: Dynamic Content', 36 | ], 37 | ) 38 | --------------------------------------------------------------------------------