strapi/website/documentation/concepts/authentication.md
2016-04-04 21:51:00 +02:00

18 KiB
Executable File

Authentication

The Strapi OAuth hook allows you to easily connect your application to 150+ providers.

Overview

OAuth is used by the web service providers to provide access to user resources in a secure manner. Each developer using this service must create an OAuth application and, after, requires the user to grant access to it.

As a part of the OAuth flow, the user is redirected to the web service's server, to log in (this step can be omitted if the user has already logged in).

Once the user agrees to use the application, he's redirected back to your website with the generated access token. We need to store that token and send it along, with each request made, to the service on behalf of the user.

Strapi enables you to add support for multiple providers through a simple and straightforward configuration data structure. This allows you to easily implement login forms with support for multiple options so your users can log in using different service providers.

The minimum required information to configure OAuth properly is:

  • consumer_key and consumer_secret or client_id and client_secret.
  • redirect or callback URL pointing back to your website.

Strapi requires that the redirect/callback URL specified in your OAuth application should have this format:

[protocol]://[host]/connect/[provider]/callback

Typical flow

  1. Register OAuth application on your provider's web site.

  2. For redirect URL of your OAuth application always use this format: [protocol]://[host]/connect/[provider]/callback

  3. Create a authentication.json in each environment (since you'll use different credentials) file containing:

{
  "authentication": {
    "facebook": {
      "key": "[CLIENT_ID]",
      "secret": "[CLIENT_SECRET]",
      "callback": "/handle_facebook_response"
    },
    "twitter": {
      "key": "[CONSUMER_KEY]",
      "secret": "[CONSUMER_SECRET]",
      "callback": "/handle_twitter_response"
    }
  }
}
  1. Navigate to /connect/facebook to initiate the OAuth flow for Facebook, or navigate to /connect/twitter to initiate the OAuth flow for Twitter.

  2. Once the OAuth flow is completed you will receive the response data in the /handle_facebook_response route for Facebook, and in the /handle_twitter_response route for Twitter.

Configuration

Configuration:

  • Key: authentication
  • Environment: development
  • Location: ./config/environments/development/authentication.json
  • Type: object

Example:

{
  "authentication": {
    "facebook": {
      "key": "[APP_ID]",
      "secret": "[APP_SECRET]",
      "callback": "/handle_facebook_callback"
    },
    "twitter": {
      "key": "[CONSUMER_KEY]",
      "secret": "[CONSUMER_SECRET]",
      "callback": "/handle_twitter_callback"
    }
  }
}

Options (for each provider):

  • key (string): consumer_key or client_id of your application.
  • secret (string): consumer_secret or client_secret of your application.
  • scope (array): Array of OAuth scopes to request
  • callback (string): Specific callback to use for this provider.
  • custom_params (object): Some providers may employ custom authorization parameters outside of the ones specified in the configuration section. You can pass those custom parameters using the custom_params option:
{
  "authentication": {
    "google": {
      "custom_params": {
        "access_type": "offline"
      }
    },
    "reddit": {
      "custom_params": {
        "duration": "permanent"
      }
    },
    "trello": {
      "custom_params": {
        "name": "my app",
        "expiration": "never"
      }
    }
  }
}

Usage

Each key is a provider that you'll want to configure and use in your application. You want to configure and use both Twitter and Facebook. The key and the secret keys are required and they must contain the credentials for your OAuth application.

The callback key is the route on your server where you want to receive the access tokens after the OAuth flow is completed.

First, you need to register your callback route for each provider. Keeping the previous example, it should look like this:

{
  "routes": {
    "GET /handle_facebook_callback": {
      "controller": "User",
      "action": "registerFacebook",
      "policies": []
    },
    "GET /handle_twitter_callback": {
      "controller": "User",
      "action": "registerTwitter",
      "policies": []
    }
  }
}

Then, you need to create an action for the route. Here is a simple example:

// Action to handle Facebook registration in the `User` controller.
registerFacebook: function * () {
  this.body = JSON.stringify(this.query, null, 2)
},

// Action to handle Twitter registration in the `User` controller.
registerTwitter: function * () {
  this.body = JSON.stringify(this.query, null, 2)
}

Specific configuration options

There are a few more configuration options that you might want to use.

scope

Some service providers allow us to configure the permissions that our application will request from the user. These permissions are set inside the scope key of the configuration:

{
  "authentication": {
    "facebook": {
      "key": "[APP_ID]",
      "secret": "[APP_SECRET]",
      "callback": "/handle_facebook_callback",
      "scope": [
        "user_groups",
        "user_likes"
      ]
    }
  }
}

In this case, the user will be asked to grant access to its groups and likes on Facebook.

state

Some providers require us to send a CORS token to ensure that the flow was initiated from our own server. The state key in the configuration can be used for that purpose:

{
  "authentication": {
    "facebook": {
      "key": "[APP_ID]",
      "secret": "[APP_SECRET]",
      "callback": "/handle_facebook_callback",
      "scope": [
        "user_groups",
        "user_likes"
      ],
      "state": "very secret"
    }
  }
}

Sandbox Redirect URI

Very rarely you may need to override the default redirect_uri that Strapi generates for you.

For example Feedly supports only http://localhost as redirect URL of their Sandbox OAuth application, and it won't allow the http://localhost/connect/feedly/callback path:

{
  "authentication": {
    "feedly": {
      "redirect_uri": "http://localhost"
    }
  }
}

In case you override the redirect_uri in your config, you'll have to redirect the user to the [protocol]://[host]/connect/[provider]/callback route that Strapi uses to execute the last step of the OAuth flow using sessions and this.redirect.

After that you will receive the results from the OAuth flow inside the route specified in the callback key of your configuration.

Quirks

Subdomain

Some providers require you to set your company name as a subdomain in the OAuth URLs. For example for Freshbooks, Shopify, Vend and Zendesk you can set that value through the subdomain option:

{
  "authentication": {
    "shopify": {
      "subdomain": "mycompany"
    }
  }
}

Then Strapi will generate the correct OAuth URLs:

{
  "authentication": {
    "shopify": {
      "authorize_url": "https://mycompany.myshopify.com/admin/oauth/authorize",
      "access_url": "https://mycompany.myshopify.com/admin/oauth/access_token"
    }
  }
}

Alternatively you can override the entire request_url, authorize_url and access_url in your configuration.

Sandbox URLs

Some providers may have sandbox URLs for testing. To use them just override the entire request_url, authorize_url and access_url in your configuration:

{
  "authentication": {
    "paypal": {
      "authorize_url": "https://www.sandbox.paypal.com/webapps/auth/protocol/openidconnect/v1/authorize",
      "access_url": "https://api.sandbox.paypal.com/v1/identity/openidconnect/tokenservice"
    },
    "evernote": {
      "request_url": "https://sandbox.evernote.com/oauth",
      "authorize_url": "https://sandbox.evernote.com/OAuth.action",
      "access_url": "https://sandbox.evernote.com/oauth"
    }
  }
}

Flickr, Optimizely

Flickr uses a custom authorization parameter to pass its scopes called perms, and Optimizely uses scopes. However you should use the regular scope option in your configuration:

{
  "authentication": {
    "flickr": {
      "scope": ["write"]
    }
    "optimizely": {
      "scope": ["all"]
    }
  }
}

SurveyMonkey

For SurveyMonkey set your Mashery user name as key and your application key as api_key:

{
  "authentication": {
    "surveymonkey": {
      "key": "[MASHERY_USER_NAME]",
      "secret": "[CLIENT_SECRET]",
      "api_key": "[CLIENT_ID]"
    }
  }
}

Fitbit, LinkedIn, ProjectPlace

Initially these providers supported only OAuth1, so the fitbit and linkedin names are used for that. To use their OAuth2 flow append 2 at the end of their names:

{
  "authentication": {
    "fitbit2": {},
    "linkedin2": {},
    "projectplace2": {}
  }
}

Response Data

The OAuth response data is returned as a querystring in your final callback - the one you specify in the callback key of your Strapi configuration.

OAuth1

For OAuth1 the access_token and the access_secret are accessible directly, raw contains the raw response data:

{
  access_token: '...',
  access_secret: '...',
  raw: {
    oauth_token: '...',
    oauth_token_secret: '...',
    some: 'other data'
  }
}

OAuth2

For OAuth2 the access_token and the refresh_token (if present) are accessible directly, raw contains the raw response data:

{
  access_token: '...',
  refresh_token: '...',
  raw: {
    access_token: '...',
    refresh_token: '...',
    some: 'other data'
  }
}

Error

In case of an error, the error key will be populated with the raw error data:

{
  error: {
    some: 'error data'
  }
}

Bypass unauthorized localhost

You should keep in mind that not all web service providers allow localhosts as a value for the OAuth application redirect URL. The easiest way to get around this is to add a new entry to your host's file like this:

127.0.0.1      mywebsite.com

If you need to use a different URL than your localhost you also need to override your server config for the authentication key like this:

{
  "authentication": {
    "server": {
      "protocol": "http",
      "host": "mywebsite.com:3000"
    },
    "facebook": {
      "key": "[APP_ID]",
      "secret": "[APP_SECRET]",
      "callback": "/handle_facebook_callback",
      "scope": [
        "user_groups",
        "user_likes"
      ]
    },
    "twitter": {
      "key": "[CONSUMER_KEY]",
      "secret": "[CONSUMER_SECRET]",
      "callback": "/handle_twitter_callback"
    }
  }
}

The server key is required and it contains the host name of your server and the protocol you're running your site on.

Providers

Supported providers

Custom providers

In case you have a private OAuth provider that is not part of the officially supported ones, you can define it in your configuration by adding a custom key for it.

In this case you have to specify all of the required provider keys by yourself:

{
  "authentication": {
    "mywebsite": {
      "authorize_url": "https://mywebsite.com/authorize",
      "access_url": "https://mywebsite.com/token",
      "oauth": 2,
      "key": "[CLIENT_ID]",
      "secret": "[CLIENT_SECRET]",
      "scope": [
        "read",
        "write"
      ]
    }
  }
}