Skip to content

Commit

Permalink
Merge pull request #2 from sailscastshq/feat/add-google-provider
Browse files Browse the repository at this point in the history
[feat] add google provider
  • Loading branch information
DominusKelvin authored Jul 3, 2023
2 parents 2ec278e + 3f40c4c commit f11c718
Show file tree
Hide file tree
Showing 10 changed files with 10,919 additions and 60 deletions.
22 changes: 22 additions & 0 deletions .github/workflows/prettier.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
name: Prettier

on: [push, pull_request]

jobs:
prettier:
runs-on: ubuntu-latest

steps:
- name: Checkout code
uses: actions/checkout@v3

- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: 18

- name: Run npm ci
run: npm ci

- name: Run Prettier
run: npx prettier --write .
4 changes: 4 additions & 0 deletions .husky/commit-msg
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"

npx --no -- commitlint --edit ${1}
4 changes: 4 additions & 0 deletions .husky/pre-commit
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"

npx lint-staged
80 changes: 80 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
# wish contributing guidelines

Thank you for taking the time to contribute to our project. We appreciate you! 🫶🏽 Please take a moment to read the following guidelines before contributing:

> ⚠️IMPORTANT **Note**
>
> **Pull Requests having no issue associated with them will not be accepted. Firstly get an issue assigned, whether it's already opened or raised by you, and then create a Pull Request.**
## Prerequisites

Before you contribute to wish, make sure you have the following prerequisites:

- Open Source Etiquette: If you've never contributed to an open source project before, have a read of [Basic etiquette](https://developer.mozilla.org/en-US/docs/MDN/Community/Open_source_etiquette) for open source projects.

- Basic familiarity with Git and GitHub: If you are also new to these tools, visit [GitHub for complete beginners](https://developer.mozilla.org/en-US/docs/MDN/Contribute/GitHub_beginners) for a comprehensive introduction to them

- [Node.js](https://nodejs.org/) is installed.

---

## How to Contribute 🤔

To contribute to wish, follow these steps:

- Look at the existing [**Issues**](https://github.com/sailscastshq/boring-stack/issues) or create a new issue if you haven't found a suitable one.
- [**Fork the Repo**](https://github.com/sailscastshq/boring-stack/issues) and create a branch for the specific issue you are working on. Let's start making a difference together! 😊
- Create a **[Pull Request](https://github.com/sailscastshq/boring-stack)** (_PR_), which will be reviewed and given suggestions for improvements by the maintatiner.
- If applicable, include screenshots or screen captures in your Pull Request to help us better understand the impact of your proposed changes.

---

## Submission Guidelines 📝

### Branch Organization

At The Boring JavaScript Stack, we use the [Gitflow branching model](https://www.atlassian.com/git/tutorials/comparing-workflows/gitflow-workflow) where we use a `develop` branch as the main branch for active development. Therefore, all Pull Requests should be directed towards the `develop` branch instead of the `main` branch. This helps us maintain a stable `main` branch while allowing continuous development on the `develop` branch.

### Good First Issue

If you're new to our project, we recommend starting with the [_Good first issue_](https://github.com/sailscastshq/sails-hook-wish/issues?q=is:open+is:issue+label:%22good+first+issue%22)label. These issues are ideal for getting familiar with the project and making your first contribution. Before starting work, please confirm with the maintainers that the issue is still relevant. Feel free to comment on the issue to express your intention and avoid duplicate efforts.

### Sending a Pull Request

To ensure a smooth review process, please follow these guidelines:

- Fork (https://help.github.com/articles/fork-a-repo) the repository into your own account.
- In your forked repository, create a new branch: `git checkout -b my-branch develop`
- Make your changes/fixes.
- Commit your code with a good commit message [using "Conventionalcommits"](https://www.conventionalcommits.org/en/v1.0.0/).
- Push your branch to GitHub: `git push origin my-branch`
- [Open a Pull Request](https://help.github.com/articles/using-pull-requests/) with a clear title and description matching the issue you intend to solve.

> ⚠️IMPORTANT **Note**
>
> ** To ensure a better review experience, we kindly request that you use the following format for the PR title: `[chore]`, `[feat]`, or `[fix]`, followed by a descriptive title. For example, a chore-related change could have a title like `[chore] Update contributing guidelines`. This helps us categorize and understand the nature of the changes made in each PR..**
- Link the issue you have resolved in the Pull Request Template using the following syntax:
- If your Pull Request fixes issue #25, add `Fixes #25` or `Closes #25` to the description.
- If your Pull Request addresses multiple issues, list them using the same syntax (`Fixes #23, Fixes #15`).

This helps us track and automatically close the relevant issue when your Pull Request is merged.

### Commits

We highly encourage the use of conventional commits. Here are some examples:

- feat: Use this when adding a new feature.
- fix: Use this when resolving any issues in the codebase.
- chore: Use this when adding new links/resources or making minor changes.
(ex. chore: Add 'Privacy Policy' link in footer)
- Please keep your commit messages concise and clear.
- Write commit messages in the present tense, as they represent the current state of the codebase after the changes have been applied.

For additional reference, check out [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/)

## Your Feedback Matters! 💬

- If you notice any missing information or feel that something is not adequately described, please don't hesitate to create a pull request (PR) or [raise an issue](https://github.com/sailscastshq/sails-hook-wish/issues). Your input helps us improve our guidelines and make the Boring-Stack project even more awesome!

We're thrilled to have you on board. Let's make a difference together! 🚀
169 changes: 164 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,21 +1,27 @@
# wish

wish is the OAuth Sails hook you wish(pun intended) exists for Sails. wish provides a simple, convenient way to authenticate with OAuth providers. wish currently supports authentication via GitHub
wish is the OAuth Sails hook you wish(pun intended) exists for Sails. wish provides a simple, convenient way to authenticate with OAuth providers.

## Supported OAuth Providers

- [GitHub](#github)
- [Google](#google)

## Installation
In your Sails project run the below command to install wish and it's node-fetch peer-dependency:

In your Sails project run the below command to install wish and it's `node-fetch` peer-dependency:

```sh
npm i --save sails-hook-wish @sailscasts/sails-hook-node-fetch
```

## Basic usage

## GitHub

To setup up a GitHub OAuth for your app, `wish` expects the following key and property in either `config/local.js` or `config/custom.js`. For example you can have a development GitHub clientId and clientSecret in `config/local.js`

> Do make sure to get the needed `clientId` and `clientSecret` credentials from GitHub. You can see [here](https://docs.github.com/en/apps/oauth-apps/building-oauth-apps/creating-an-oauth-app) for instructions on how to get those credentials
```js
//
github: {
clientId: 'CLIENT_ID',
clientSecret: 'CLIENT_SECRET',
Expand All @@ -37,13 +43,15 @@ github: {
> Notice I am using environment variables as it's best practice not to commit your secret credentials. In the case of `local.js` that's okay because that file is never committed to version control.
### The redirect

A typical flow is to have a button on your website say like "Sign in with GitHub". A good example can be found [here](https://sailscasts.com/signin)

Clicking that button should call a redirect route you've set in `routes.js`

```js
'GET /auth/redirect': 'auth/redirect',
```

Now let's author this `auth/redirect` action:

```js
Expand Down Expand Up @@ -155,6 +163,157 @@ The above is an actual real world use case of wish in [https://sailscasts.com](h

There you have it, a GitHub OAuth flow with just two routes and one line of code each to both redirect to GitHub and get the OAuth user details.

## Google

To setup up a Google OAuth for your app, `wish` expects the following key and property in either `config/local.js` or `config/custom.js`. For example you can have a development Google `clientId` and `clientSecret` in `config/local.js`

> Do make sure to get the needed `clientId` and `clientSecret` credentials from the Google Console. You can see [here](https://developers.google.com/identity/protocols/oauth2) for instructions on how to get those credentials
```js
google: {
clientId: 'CLIENT_ID',
clientSecret: 'CLIENT_SECRET',
redirect: 'http://localhost:1337/auth/callback',
},
```

You can override this value for production in either `custom.js` or in an environment specific `custom.js`. I personally set this up for https://sailscasts.com to override the `local.js` value so I can have 3 environments with 3 different `clientId`, `clientSecret`, and `redirect` values.

```js
// custom.js
google: {
clientId: process.env.GOOGLE_CLIENT_ID,
clientSecret: process.env.GOOGLE_CLIENT_SECRET,
redirect: 'https://example.com/auth/callback',
},
```

> Notice I am using environment variables as it's best practice not to commit your secret credentials. In the case of `local.js` that's okay because that file is never committed to version control.
### The redirect

A typical flow is to have a button on your website say like "Sign in with Google". A good example is implemented in [The Boring JavaScript Stack](https://sailscasts.com/boring) mellow template

Clicking that button should call a redirect route you've set in `routes.js`

```js
'GET /auth/redirect': 'auth/redirect',
```

Now let's author this `auth/redirect` action:

```js
module.exports = {
friendlyName: 'Redirect',

description: 'Redirect auth.',

inputs: {},

exits: {
success: {
responseType: 'redirect',
},
},

fn: async function () {
return sails.wish.provider('google').redirect()
},
}
```

Notice the redirect is a one-line of code and when this action is called, it will redirect to GitHub to begin the OAuth process.

## The callback

Note the callback URL we set above that `wish` will callback? Let's also implement that starting from the route in `routes.js`

```js
'GET /auth/callback': 'auth/callback',
```

```js
module.exports = {
friendlyName: 'Callback',

description: 'Callback auth.',

inputs: {
code: {
type: 'string',
required: true,
},
},

exits: {
success: {
responseType: 'redirect',
},
},

fn: async function ({ code }, exits) {
const req = this.req

// Get the Google user info
const googleUser = await sails.wish.provider('google').user(code)

User.findOrCreate(
{ googleId: googleUser.id },
{
id: sails.helpers.getUuid(),
googleId: googleUser.id,
email: googleUser.email,
name: googleUser.name,
googleAvatarUrl: googleUser.picture,
googleAccessToken: googleUser.accessToken,
googleIdToken: googleUser.idToken,
}
).exec(async (error, user, wasCreated) => {
if (error) throw error

// Checks if the user email has changed since last log in
// And then update the email change candidate which will be used be used to prompt the user to update their email
if (!wasCreated && user.email !== googleUser.email) {
await User.updateOne({ id: user.id }).set({
emailChangeCandidate: googleUser.email,
})
}

if (!wasCreated && user.name !== googleUser.name) {
await User.updateOne({ id: user.id }).set({
name: googleUser.name,
})
}

if (!wasCreated && user.googleAvatarUrl !== googleUser.picture) {
await User.updateOne({ id: user.id }).set({
googleAvatarUrl: googleUser.picture,
})
}

if (!wasCreated && user.googleAccessToken !== googleUser.accessToken) {
await User.updateOne({ id: user.id }).set({
googleAccessToken: googleUser.accessToken,
})
}

if (!wasCreated && user.googleIdToken !== googleUser.idToken) {
await User.updateOne({ id: user.id }).set({
googleIdToken: googleUser.idToken,
})
}

// Modify the active session instance.
// (This will be persisted when the response is sent.)
req.session.userId = user.id
return exits.success('/')
})
},
}
```

There you have it, a Google OAuth flow with just two routes and one line of code each to both redirect to Google and get the OAuth user details.

## License

wish is open-sourced software licensed under the MIT license.
1 change: 1 addition & 0 deletions commitlint.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
module.exports = { extends: ['@commitlint/config-conventional'] }
Loading

0 comments on commit f11c718

Please sign in to comment.