├── .gitignore ├── LICENSE ├── README.md ├── django ├── .gitignore ├── apps │ └── example │ │ ├── __init__.py │ │ ├── admin.py │ │ ├── apps.py │ │ ├── migrations │ │ └── __init__.py │ │ ├── models.py │ │ ├── serializers.py │ │ ├── tests.py │ │ └── views.py ├── manage.py ├── media │ └── .gitkeep ├── project │ ├── __init__.py │ ├── asgi.py │ ├── settings.py │ ├── urls.py │ └── wsgi.py ├── requirements.txt ├── static │ └── .gitkeep └── templates │ └── .gitkeep └── nextjs ├── .env.local.example ├── .github └── FUNDING.yml ├── .gitignore ├── LICENSE ├── README.md ├── components ├── access-denied.js ├── footer.js ├── footer.module.css ├── header.js ├── header.module.css └── layout.js ├── middleware.js ├── package-lock.json ├── package.json └── pages ├── _app.js ├── admin.js ├── api-example.js ├── api ├── auth │ └── [...nextauth].js └── examples │ ├── jwt.js │ ├── protected.js │ └── session.js ├── client.js ├── index.js ├── me.js ├── policy.js ├── protected.js ├── server.js └── styles.css /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Mark Hill 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # NextAuth.js Django Provider Example 2 | 3 | Example of using NextAuth.js with a Django (DRF & JWT) backend. 4 | 5 | This repository contains: 6 | 7 | 1. [Django](https://www.djangoproject.com/) backend with a Django Rest Framework API supporting authentication using JWT. 8 | 2. [NextAuth.js](https://next-auth.js.org/) application with a Django JWT provider. 9 | 10 | **Note:** The main inspiration comes from this [thread](https://github.com/nextauthjs/next-auth/discussions/1350) and in particular [this contribution](https://github.com/nextauthjs/next-auth/discussions/1350#discussioncomment-2145362) by [mojtabajahannia](https://github.com/mojtabajahannia). 11 | 12 | Not sure if this is the best approach, so all suggestions welcome. 13 | 14 | ## Django 15 | 16 | ### Environment 17 | 18 | ``` 19 | cd django 20 | python3 -m venv ./env 21 | source ./env/bin/activate 22 | ``` 23 | 24 | ### Installation 25 | 26 | ``` 27 | pip install --upgrade pip 28 | pip install -r ./requirements.txt 29 | ``` 30 | 31 | ### Setup 32 | 33 | ``` 34 | python manage.py makemigrations 35 | python manage.py migrate 36 | ``` 37 | 38 | ### Admin 39 | 40 | Add admin user to demonstrate unrestricted access to all client-side routes. 41 | 42 | ``` 43 | python manage.py createsuperuser 44 | ``` 45 | 46 | ### Visitor 47 | 48 | Add an ordinary user to demonstrate restricted access to client-side /admin route. 49 | 50 | ``` 51 | python manage.py shell 52 | 53 | >>> from django.contrib.auth.models import User 54 | >>> user=User.objects.create_user('visitor', password='visitor') 55 | >>> user.save() 56 | >>> exit() 57 | ``` 58 | 59 | ### Start 60 | 61 | ``` 62 | python manage.py runserver 63 | ``` 64 | 65 | ## Next.js 66 | 67 | Install modules and run development server. 68 | 69 | ### Installation 70 | 71 | ``` 72 | cd nextjs 73 | npm install 74 | ``` 75 | 76 | ### Local environment 77 | 78 | ``` 79 | cp .env.local.example .env.local 80 | ``` 81 | 82 | ### Start 83 | 84 | ``` 85 | npm run dev 86 | ``` 87 | 88 | **Note:** Based on the original [next-auth-sample](https://github.com/nextauthjs/next-auth-example) code. 89 | -------------------------------------------------------------------------------- /django/.gitignore: -------------------------------------------------------------------------------- 1 | *.egg-info 2 | *.pot 3 | *.py[co] 4 | .tox/ 5 | __pycache__ 6 | MANIFEST 7 | dist/ 8 | docs/_build/ 9 | docs/locale/ 10 | node_modules/ 11 | tests/coverage_html/ 12 | tests/.coverage 13 | build/ 14 | tests/report/ 15 | 16 | .DS_Store 17 | 18 | env/ 19 | 20 | db.sqlite3 -------------------------------------------------------------------------------- /django/apps/example/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hillmark/next-auth-django/a6368729161aaf71c369da0df62c98e3630f71e7/django/apps/example/__init__.py -------------------------------------------------------------------------------- /django/apps/example/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | 3 | # Register your models here. 4 | -------------------------------------------------------------------------------- /django/apps/example/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class ExampleConfig(AppConfig): 5 | default_auto_field = 'django.db.models.BigAutoField' 6 | name = 'apps.example' 7 | -------------------------------------------------------------------------------- /django/apps/example/migrations/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hillmark/next-auth-django/a6368729161aaf71c369da0df62c98e3630f71e7/django/apps/example/migrations/__init__.py -------------------------------------------------------------------------------- /django/apps/example/models.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | 3 | # Create your models here. 4 | -------------------------------------------------------------------------------- /django/apps/example/serializers.py: -------------------------------------------------------------------------------- 1 | from django.contrib.auth.models import User, Group 2 | from rest_framework import serializers 3 | from rest_framework_simplejwt.serializers import TokenObtainPairSerializer 4 | 5 | 6 | class UserSerializer(serializers.HyperlinkedModelSerializer): 7 | class Meta: 8 | model = User 9 | fields = ['url', 'username', 'email', 'groups'] 10 | 11 | 12 | class GroupSerializer(serializers.HyperlinkedModelSerializer): 13 | class Meta: 14 | model = Group 15 | fields = ['url', 'name'] 16 | 17 | class ExampleTokenObtainPairSerializer(TokenObtainPairSerializer): 18 | """Customizes JWT default Serializer to add more information about user""" 19 | @classmethod 20 | def get_token(cls, user): 21 | token = super().get_token(user) 22 | token['username'] = user.username 23 | token['email'] = user.email 24 | token['is_superuser'] = user.is_superuser 25 | token['is_staff'] = user.is_staff 26 | return token -------------------------------------------------------------------------------- /django/apps/example/tests.py: -------------------------------------------------------------------------------- 1 | from django.test import TestCase 2 | 3 | # Create your tests here. 4 | -------------------------------------------------------------------------------- /django/apps/example/views.py: -------------------------------------------------------------------------------- 1 | from django.contrib.auth.models import User, Group 2 | from rest_framework import viewsets 3 | from rest_framework import permissions 4 | from rest_framework_simplejwt.views import TokenObtainPairView 5 | 6 | from .serializers import UserSerializer, GroupSerializer,ExampleTokenObtainPairSerializer 7 | 8 | 9 | class UserViewSet(viewsets.ModelViewSet): 10 | """ 11 | API endpoint that allows users to be viewed or edited. 12 | """ 13 | queryset = User.objects.all().order_by('-date_joined') 14 | serializer_class = UserSerializer 15 | permission_classes = [permissions.IsAuthenticated] 16 | 17 | 18 | class GroupViewSet(viewsets.ModelViewSet): 19 | """ 20 | API endpoint that allows groups to be viewed or edited. 21 | """ 22 | queryset = Group.objects.all() 23 | serializer_class = GroupSerializer 24 | permission_classes = [permissions.IsAuthenticated] 25 | 26 | 27 | class ExampleTokenObtainPairView(TokenObtainPairView): 28 | # Replace the serializer with your custom 29 | serializer_class = ExampleTokenObtainPairSerializer -------------------------------------------------------------------------------- /django/manage.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | """Django's command-line utility for administrative tasks.""" 3 | import os 4 | import sys 5 | 6 | 7 | def main(): 8 | """Run administrative tasks.""" 9 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'project.settings') 10 | try: 11 | from django.core.management import execute_from_command_line 12 | except ImportError as exc: 13 | raise ImportError( 14 | "Couldn't import Django. Are you sure it's installed and " 15 | "available on your PYTHONPATH environment variable? Did you " 16 | "forget to activate a virtual environment?" 17 | ) from exc 18 | execute_from_command_line(sys.argv) 19 | 20 | 21 | if __name__ == '__main__': 22 | main() 23 | -------------------------------------------------------------------------------- /django/media/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hillmark/next-auth-django/a6368729161aaf71c369da0df62c98e3630f71e7/django/media/.gitkeep -------------------------------------------------------------------------------- /django/project/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hillmark/next-auth-django/a6368729161aaf71c369da0df62c98e3630f71e7/django/project/__init__.py -------------------------------------------------------------------------------- /django/project/asgi.py: -------------------------------------------------------------------------------- 1 | """ 2 | ASGI config for project project. 3 | 4 | It exposes the ASGI callable as a module-level variable named ``application``. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/3.2/howto/deployment/asgi/ 8 | """ 9 | 10 | import os 11 | 12 | from django.core.asgi import get_asgi_application 13 | 14 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'project.settings') 15 | 16 | application = get_asgi_application() 17 | -------------------------------------------------------------------------------- /django/project/settings.py: -------------------------------------------------------------------------------- 1 | """ 2 | Django settings for project project. 3 | 4 | Generated by 'django-admin startproject' using Django 3.2.15. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/3.2/topics/settings/ 8 | 9 | For the full list of settings and their values, see 10 | https://docs.djangoproject.com/en/3.2/ref/settings/ 11 | """ 12 | import os 13 | 14 | from pathlib import Path 15 | 16 | # Build paths inside the project like this: BASE_DIR / 'subdir'. 17 | BASE_DIR = Path(__file__).resolve().parent.parent 18 | 19 | 20 | # Quick-start development settings - unsuitable for production 21 | # See https://docs.djangoproject.com/en/3.2/howto/deployment/checklist/ 22 | 23 | # SECURITY WARNING: keep the secret key used in production secret! 24 | SECRET_KEY = 'django-insecure-t%cgmm5zkgtfx&#!!*+ry&cqz^ei7ylc7$l&n5iu1ukzk5slri' 25 | 26 | # SECURITY WARNING: don't run with debug turned on in production! 27 | DEBUG = True 28 | 29 | ALLOWED_HOSTS = [] 30 | 31 | 32 | # Application definition 33 | 34 | INSTALLED_APPS = [ 35 | 'django.contrib.admin', 36 | 'django.contrib.auth', 37 | 'django.contrib.contenttypes', 38 | 'django.contrib.sessions', 39 | 'django.contrib.messages', 40 | 'django.contrib.staticfiles', 41 | # vendor 42 | 'corsheaders', 43 | 'rest_framework', 44 | # custom 45 | 'apps.example' 46 | ] 47 | 48 | MIDDLEWARE = [ 49 | 'django.middleware.security.SecurityMiddleware', 50 | 'django.contrib.sessions.middleware.SessionMiddleware', 51 | 'corsheaders.middleware.CorsMiddleware', # cors 52 | 'django.middleware.common.CommonMiddleware', 53 | 'django.middleware.csrf.CsrfViewMiddleware', 54 | 'django.contrib.auth.middleware.AuthenticationMiddleware', 55 | 'django.contrib.messages.middleware.MessageMiddleware', 56 | 'django.middleware.clickjacking.XFrameOptionsMiddleware', 57 | ] 58 | 59 | ROOT_URLCONF = 'project.urls' 60 | 61 | TEMPLATES = [ 62 | { 63 | 'BACKEND': 'django.template.backends.django.DjangoTemplates', 64 | 'DIRS': [BASE_DIR / 'templates/',], 65 | 'APP_DIRS': True, 66 | 'OPTIONS': { 67 | 'context_processors': [ 68 | 'django.template.context_processors.debug', 69 | 'django.template.context_processors.request', 70 | 'django.contrib.auth.context_processors.auth', 71 | 'django.contrib.messages.context_processors.messages', 72 | ], 73 | }, 74 | }, 75 | ] 76 | 77 | WSGI_APPLICATION = 'project.wsgi.application' 78 | 79 | 80 | # Database 81 | # https://docs.djangoproject.com/en/3.2/ref/settings/#databases 82 | 83 | DATABASES = { 84 | 'default': { 85 | 'ENGINE': 'django.db.backends.sqlite3', 86 | 'NAME': BASE_DIR / 'db.sqlite3', 87 | } 88 | } 89 | 90 | 91 | # Password validation 92 | # https://docs.djangoproject.com/en/3.2/ref/settings/#auth-password-validators 93 | 94 | AUTH_PASSWORD_VALIDATORS = [ 95 | { 96 | 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', 97 | }, 98 | { 99 | 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', 100 | }, 101 | { 102 | 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', 103 | }, 104 | { 105 | 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', 106 | }, 107 | ] 108 | 109 | 110 | # Internationalization 111 | # https://docs.djangoproject.com/en/3.2/topics/i18n/ 112 | 113 | LANGUAGE_CODE = 'en-us' 114 | 115 | TIME_ZONE = 'UTC' 116 | 117 | USE_I18N = True 118 | 119 | USE_L10N = True 120 | 121 | USE_TZ = True 122 | 123 | 124 | # Static files (CSS, JavaScript, Images) 125 | # https://docs.djangoproject.com/en/3.2/howto/static-files/ 126 | 127 | STATIC_URL = '/static/' 128 | 129 | # Default primary key field type 130 | # https://docs.djangoproject.com/en/3.2/ref/settings/#default-auto-field 131 | 132 | DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField' 133 | 134 | REST_FRAMEWORK = { 135 | 'DEFAULT_AUTHENTICATION_CLASSES': ( 136 | 'rest_framework_simplejwt.authentication.JWTAuthentication', 137 | ), 138 | 'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination', 139 | 'PAGE_SIZE': 10 140 | } 141 | 142 | CORS_ALLOWED_ORIGINS = [ 143 | 'http://localhost:3000', 144 | ] 145 | 146 | # Static files (CSS, JavaScript, Images) 147 | STATIC_URL = '/static/' 148 | STATIC_ROOT = os.path.join(BASE_DIR, 'static/') 149 | 150 | # Media Files 151 | MEDIA_ROOT = os.path.join(BASE_DIR, 'media') 152 | MEDIA_URL = '/media/' -------------------------------------------------------------------------------- /django/project/urls.py: -------------------------------------------------------------------------------- 1 | """project URL Configuration 2 | 3 | The `urlpatterns` list routes URLs to views. For more information please see: 4 | https://docs.djangoproject.com/en/3.2/topics/http/urls/ 5 | Examples: 6 | Function views 7 | 1. Add an import: from my_app import views 8 | 2. Add a URL to urlpatterns: path('', views.home, name='home') 9 | Class-based views 10 | 1. Add an import: from other_app.views import Home 11 | 2. Add a URL to urlpatterns: path('', Home.as_view(), name='home') 12 | Including another URLconf 13 | 1. Import the include() function: from django.urls import include, path 14 | 2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) 15 | """ 16 | from django.contrib import admin 17 | from django.urls import include, path 18 | from rest_framework import routers 19 | from rest_framework_simplejwt.views import ( 20 | TokenObtainPairView, 21 | TokenRefreshView, 22 | TokenVerifyView 23 | ) 24 | from apps.example import views 25 | from apps.example.views import ( 26 | ExampleTokenObtainPairView 27 | ) 28 | 29 | router = routers.DefaultRouter() 30 | router.register(r'users', views.UserViewSet) 31 | router.register(r'groups', views.GroupViewSet) 32 | 33 | urlpatterns = [ 34 | path('admin/', admin.site.urls), 35 | path('api/', include(router.urls)), 36 | path('api-auth/', include('rest_framework.urls', namespace='rest_framework')), 37 | path('api/token/', ExampleTokenObtainPairView.as_view(), name='token_obtain_pair'), 38 | path('api/token/refresh/', TokenRefreshView.as_view(), name='token_refresh'), 39 | path('api/token/verify/', TokenVerifyView.as_view(), name='token_verify'), 40 | ] -------------------------------------------------------------------------------- /django/project/wsgi.py: -------------------------------------------------------------------------------- 1 | """ 2 | WSGI config for project project. 3 | 4 | It exposes the WSGI callable as a module-level variable named ``application``. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/3.2/howto/deployment/wsgi/ 8 | """ 9 | 10 | import os 11 | 12 | from django.core.wsgi import get_wsgi_application 13 | 14 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'project.settings') 15 | 16 | application = get_wsgi_application() 17 | -------------------------------------------------------------------------------- /django/requirements.txt: -------------------------------------------------------------------------------- 1 | Django==3.2.15 2 | django-cors-headers==3.13.0 3 | djangorestframework==3.14.0 4 | djangorestframework-simplejwt==5.2.0 5 | 6 | -------------------------------------------------------------------------------- /django/static/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hillmark/next-auth-django/a6368729161aaf71c369da0df62c98e3630f71e7/django/static/.gitkeep -------------------------------------------------------------------------------- /django/templates/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hillmark/next-auth-django/a6368729161aaf71c369da0df62c98e3630f71e7/django/templates/.gitkeep -------------------------------------------------------------------------------- /nextjs/.env.local.example: -------------------------------------------------------------------------------- 1 | NEXTAUTH_URL=http://localhost:3000 2 | NEXTAUTH_SECRET= # Linux: `openssl rand -hex 32` or go to https://generate-secret.now.sh/32 3 | 4 | APPLE_ID= 5 | APPLE_TEAM_ID= 6 | APPLE_PRIVATE_KEY= 7 | APPLE_KEY_ID= 8 | 9 | AUTH0_ID= 10 | AUTH0_SECRET= 11 | AUTH0_ISSUER= 12 | 13 | FACEBOOK_ID= 14 | FACEBOOK_SECRET= 15 | 16 | GITHUB_ID= 17 | GITHUB_SECRET= 18 | 19 | GOOGLE_ID= 20 | GOOGLE_SECRET= 21 | 22 | TWITTER_ID= 23 | TWITTER_SECRET= 24 | 25 | EMAIL_SERVER=smtp://username:password@smtp.example.com:587 26 | EMAIL_FROM=NextAuth 27 | 28 | DATABASE_URL=sqlite://localhost/:memory:?synchronize=true 29 | -------------------------------------------------------------------------------- /nextjs/.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # https://docs.github.com/en/github/administering-a-repository/displaying-a-sponsor-button-in-your-repository 2 | 3 | open_collective: nextauth 4 | github: [balazsorban44] 5 | -------------------------------------------------------------------------------- /nextjs/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | 3 | node_modules/ 4 | logs 5 | *.log 6 | npm-debug.log* 7 | yarn-debug.log* 8 | yarn-error.log* 9 | lerna-debug.log* 10 | .yarn-integrity 11 | .npm 12 | 13 | .eslintcache 14 | 15 | *.tsbuildinfo 16 | next-env.d.ts 17 | 18 | .next 19 | .vercel 20 | .env*.local -------------------------------------------------------------------------------- /nextjs/LICENSE: -------------------------------------------------------------------------------- 1 | ISC License 2 | 3 | Copyright (c) 2018-2021, Iain Collins 4 | 5 | Permission to use, copy, modify, and/or distribute this software for any 6 | purpose with or without fee is hereby granted, provided that the above 7 | copyright notice and this permission notice appear in all copies. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 | ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -------------------------------------------------------------------------------- /nextjs/README.md: -------------------------------------------------------------------------------- 1 | > The example repository is maintained from a [monorepo](https://github.com/nextauthjs/next-auth/tree/main/apps/example-nextjs). Pull Requests should be opened against [`nextauthjs/next-auth`](https://github.com/nextauthjs/next-auth). 2 | 3 |

4 |
5 | 6 |

NextAuth.js Example App

7 |

8 | Open Source. Full Stack. Own Your Data. 9 |

10 |

11 | 12 | npm 13 | 14 | 15 | Bundle Size 16 | 17 | 18 | Downloads 19 | 20 | 21 | TypeScript 22 | 23 |

24 |

25 | 26 | ## Overview 27 | 28 | NextAuth.js is a complete open source authentication solution. 29 | 30 | This is an example application that shows how `next-auth` is applied to a basic Next.js app. 31 | 32 | The deployed version can be found at [`next-auth-example.vercel.app`](https://next-auth-example.vercel.app) 33 | 34 | ### About NextAuth.js 35 | 36 | NextAuth.js is an easy to implement, full-stack (client/server) open source authentication library originally designed for [Next.js](https://nextjs.org) and [Serverless](https://vercel.com). Our goal is to [support even more frameworks](https://github.com/nextauthjs/next-auth/issues/2294) in the future. 37 | 38 | Go to [next-auth.js.org](https://next-auth.js.org) for more information and documentation. 39 | 40 | > *NextAuth.js is not officially associated with Vercel or Next.js.* 41 | 42 | ## Getting Started 43 | 44 | ### 1. Clone the repository and install dependencies 45 | 46 | ``` 47 | git clone https://github.com/nextauthjs/next-auth-example.git 48 | cd next-auth-example 49 | npm install 50 | ``` 51 | 52 | ### 2. Configure your local environment 53 | 54 | Copy the .env.local.example file in this directory to .env.local (which will be ignored by Git): 55 | 56 | ``` 57 | cp .env.local.example .env.local 58 | ``` 59 | 60 | Add details for one or more providers (e.g. Google, Twitter, GitHub, Email, etc). 61 | 62 | #### Database 63 | 64 | A database is needed to persist user accounts and to support email sign in. However, you can still use NextAuth.js for authentication without a database by using OAuth for authentication. If you do not specify a database, [JSON Web Tokens](https://jwt.io/introduction) will be enabled by default. 65 | 66 | You **can** skip configuring a database and come back to it later if you want. 67 | 68 | For more information about setting up a database, please check out the following links: 69 | 70 | * Docs: [next-auth.js.org/adapters/overview](https://next-auth.js.org/adapters/overview) 71 | 72 | ### 3. Configure Authentication Providers 73 | 74 | 1. Review and update options in `pages/api/auth/[...nextauth].js` as needed. 75 | 76 | 2. When setting up OAuth, in the developer admin page for each of your OAuth services, you should configure the callback URL to use a callback path of `{server}/api/auth/callback/{provider}`. 77 | 78 | e.g. For Google OAuth you would use: `http://localhost:3000/api/auth/callback/google` 79 | 80 | A list of configured providers and their callback URLs is available from the endpoint `/api/auth/providers`. You can find more information at https://next-auth.js.org/configuration/providers/oauth 81 | 82 | 3. You can also choose to specify an SMTP server for passwordless sign in via email. 83 | 84 | ### 4. Start the application 85 | 86 | To run your site locally, use: 87 | 88 | ``` 89 | npm run dev 90 | ``` 91 | 92 | To run it in production mode, use: 93 | 94 | ``` 95 | npm run build 96 | npm run start 97 | ``` 98 | 99 | ### 5. Preparing for Production 100 | 101 | Follow the [Deployment documentation](https://next-auth.js.org/deployment) 102 | 103 | ## Acknowledgements 104 | 105 | 106 | Powered By Vercel 107 | 108 |

Thanks to Vercel sponsoring this project by allowing it to be deployed for free for the entire NextAuth.js Team

109 | 110 | ## License 111 | 112 | ISC 113 | 114 | -------------------------------------------------------------------------------- /nextjs/components/access-denied.js: -------------------------------------------------------------------------------- 1 | import { signIn } from "next-auth/react" 2 | 3 | export default function AccessDenied() { 4 | return ( 5 | <> 6 |

Access Denied

7 |

8 | { 11 | e.preventDefault() 12 | signIn() 13 | }} 14 | > 15 | You must be signed in to view this page 16 | 17 |

18 | 19 | ) 20 | } 21 | -------------------------------------------------------------------------------- /nextjs/components/footer.js: -------------------------------------------------------------------------------- 1 | import Link from "next/link" 2 | import styles from "./footer.module.css" 3 | import packageJSON from "../package.json" 4 | 5 | export default function Footer() { 6 | return ( 7 | 27 | ) 28 | } 29 | -------------------------------------------------------------------------------- /nextjs/components/footer.module.css: -------------------------------------------------------------------------------- 1 | .footer { 2 | margin-top: 2rem; 3 | } 4 | 5 | .navItems { 6 | margin-bottom: 1rem; 7 | padding: 0; 8 | list-style: none; 9 | } 10 | 11 | .navItem { 12 | display: inline-block; 13 | margin-right: 1rem; 14 | } 15 | -------------------------------------------------------------------------------- /nextjs/components/header.js: -------------------------------------------------------------------------------- 1 | import Link from "next/link"; 2 | import { signIn, signOut, useSession } from "next-auth/react"; 3 | import styles from "./header.module.css"; 4 | 5 | // The approach used in this component shows how to build a sign in and sign out 6 | // component that works on pages which support both client and server side 7 | // rendering, and avoids any flash incorrect content on initial page load. 8 | export default function Header() { 9 | const { data: session, status } = useSession(); 10 | const loading = status === "loading"; 11 | 12 | return ( 13 |
14 | 17 |
18 |

23 | {!session && ( 24 | <> 25 | 26 | You are not signed in 27 | 28 | { 32 | e.preventDefault(); 33 | signIn(); 34 | }} 35 | > 36 | Sign in 37 | 38 | 39 | )} 40 | {session?.user && ( 41 | <> 42 | {session.user.image && ( 43 | 47 | )} 48 | 49 | Signed in as 50 |
51 | {session.user.username} 52 |
53 | { 57 | e.preventDefault(); 58 | signOut(); 59 | }} 60 | > 61 | Sign out 62 | 63 | 64 | )} 65 |

66 |
67 | 92 |
93 | ); 94 | } 95 | -------------------------------------------------------------------------------- /nextjs/components/header.module.css: -------------------------------------------------------------------------------- 1 | /* Set min-height to avoid page reflow while session loading */ 2 | .signedInStatus { 3 | display: block; 4 | min-height: 4rem; 5 | width: 100%; 6 | } 7 | 8 | .loading, 9 | .loaded { 10 | position: relative; 11 | top: 0; 12 | opacity: 1; 13 | overflow: hidden; 14 | border-radius: 0 0 0.6rem 0.6rem; 15 | padding: 0.6rem 1rem; 16 | margin: 0; 17 | background-color: rgba(0, 0, 0, 0.05); 18 | transition: all 0.2s ease-in; 19 | } 20 | 21 | .loading { 22 | top: -2rem; 23 | opacity: 0; 24 | } 25 | 26 | .signedInText, 27 | .notSignedInText { 28 | position: absolute; 29 | padding-top: 0.8rem; 30 | left: 1rem; 31 | right: 6.5rem; 32 | white-space: nowrap; 33 | text-overflow: ellipsis; 34 | overflow: hidden; 35 | display: inherit; 36 | z-index: 1; 37 | line-height: 1.3rem; 38 | } 39 | 40 | .signedInText { 41 | padding-top: 0rem; 42 | left: 4.6rem; 43 | } 44 | 45 | .avatar { 46 | border-radius: 2rem; 47 | float: left; 48 | height: 2.8rem; 49 | width: 2.8rem; 50 | background-color: white; 51 | background-size: cover; 52 | background-repeat: no-repeat; 53 | } 54 | 55 | .button, 56 | .buttonPrimary { 57 | float: right; 58 | margin-right: -0.4rem; 59 | font-weight: 500; 60 | border-radius: 0.3rem; 61 | cursor: pointer; 62 | font-size: 1rem; 63 | line-height: 1.4rem; 64 | padding: 0.7rem 0.8rem; 65 | position: relative; 66 | z-index: 10; 67 | background-color: transparent; 68 | color: #555; 69 | } 70 | 71 | .buttonPrimary { 72 | background-color: #346df1; 73 | border-color: #346df1; 74 | color: #fff; 75 | text-decoration: none; 76 | padding: 0.7rem 1.4rem; 77 | } 78 | 79 | .buttonPrimary:hover { 80 | box-shadow: inset 0 0 5rem rgba(0, 0, 0, 0.2); 81 | } 82 | 83 | .navItems { 84 | margin-bottom: 2rem; 85 | padding: 0; 86 | list-style: none; 87 | } 88 | 89 | .navItem { 90 | display: inline-block; 91 | margin-right: 1rem; 92 | } 93 | -------------------------------------------------------------------------------- /nextjs/components/layout.js: -------------------------------------------------------------------------------- 1 | import Header from "./header"; 2 | import Footer from "./footer"; 3 | 4 | export default function Layout({ children }) { 5 | return ( 6 | <> 7 |
8 |
{children}
9 |