ooade / next-apollo-auth

Authentication Boilerplate with Next.js and Apollo GraphQL
https://next-auth-apollo.now.sh
202 stars 36 forks source link
apollo authentication expressjs graphql nextjs

Auth Example with Next.js and Apollo

This example shows how to implement Authentication with Next.js and Apollo GraphQL.

Main Technologies Used

Contents

Project Structure

├── components
│   └── forms
│   ├── login.js
│   └── signup.js
├── lib
│   ├── initApollo.js
│   └── withData.js
├── pages
│   ├── index.js
│   ├── login.js
│   └── signup.js
└── server
├── data
│   ├── resolvers.js
│   └── schema.js
├── models
│   └── User.js
├── services
│   └── passport.js
└── index.js

Mutations

Schema

Here we have one User's type with three fields (email, fullname and password), one Query type with a profile field just to keep GraphQL's mouth shut about having a Query type defined. We have two Mutation types (login, and signup).

type User {
    email: String
    fullname: String
    password: String
}

type Query {
    profile: User
}

type Mutation {
    createUser(email: String!, fullname: String, password: String!): User
    login(email: String!, password: String!): User
}

Resolvers

The resolvers we care about here are createUser and login. They both take in email and password as arguments with createUser taking an extra fullname argument.

Mutation: {
        createUser(root, { email, fullname, password }, { login }) {
            const user = new User({ email, fullname })

            return new Promise((resolve, reject) => {
                return User.register(user, password, err => {
                    if (err) {
                        reject(err)
                    } else {
                        login(user, () => resolve(user))
                    }
                })
            })
        },
        login(root, { email, password }, { login }) {
            return new Promise((resolve, reject) => {
                return User.authenticate()(email, password, (err, user) => {
                    // user returns false if username / email incorrect
                    if (user) {
                        login(user, () => resolve(user))
                    } else {
                        reject('Email / Password Incorrect')
                    }
                })
            })
        }
    }

Models

Oops! We have only one model (User). It accepts email, validates the email with express-validator. Then we have a plugin to tell passport-local-mongoose to use our email field as the default usernameField.

const userSchema = new Schema({
    email: {
        type: String,
        unique: true,
        lowercase: true,
        trim: true,
        validate: {
            isAsync: true,
            validator: (v, cb) =>
                cb(validator.isEmail(v), `${v} is not a valid email address`)
        },
        required: 'Please Supply an email address'
    },
    fullname: String
})

userSchema.plugin(passportLocalMongoose, {
    usernameField: 'email',
    errorMessages: {
        UserExistsError: 'Email Already Exists'
    }
})

Deploy

Deploy to now

License

MIT