使用 Facebook 进行身份验证的网站的 REST API

我们有一个网站,其中的 只有方式登录和认证自己的网站是与 Facebook (这不是我的选择)。第一次使用 Facebook 登录时,会自动为您创建一个帐户。

现在,我们希望为我们的站点创建一个 iPhone 应用程序,并为其他人使用我们的服务创建一个公共 API。

这个问题是关于如何通过应用程序/API 认证我们的网站,分为两部分:

  1. 什么是正确的方法来处理 REST 认证从一个 API 到一个网站,只使用 Facebook OAuth 作为一种认证方法?

我已经阅读和研究了很多关于 RESTAPI 的标准身份验证方法。我们不能使用 基于 HTTPS 的基本授权这样的方法,因为这样的用户没有凭据。类似于 这个的东西似乎只用于使用 API 对应用程序进行身份验证。

目前,我能想到的最好的方法是,你在我们的 API 上点击一个/认证端点,它会重定向到 Facebook OAuth,然后重定向回站点,并提供一个“令牌”,API 的用户可以使用它来验证后续请求。

  1. 对于我们创建的官方应用程序,我们不一定需要以相同的方式使用公共 API。那么,什么是与我们的网站对话并验证用户身份的最佳方式呢?

我理解(我认为)如何验证使用我们的 API 的第三方应用程序,使用 API (公共)密钥和秘密(私有)密钥。然而,当涉及到对使用应用程序的用户进行身份验证时,当我们必须对用户进行身份验证的唯一方法是 Facebook 时,我对如何进行这项工作感到相当困惑。

我觉得我遗漏了一些非常明显的东西,或者不完全理解公共 REST API 应该如何工作,所以任何建议和帮助都将非常感谢。

40865 次浏览

I am trying to answer the same question and have been going through a lot of reading recently...

I won't have "the" answer but things are getting a little clearer for me. Have you read the comments in the article you mentioned? I found them really interesting and helpful.

As a result, and in the light of how things have evolved since the first article has been written, here's what I think I'll do:

  • HTTPS everywhere — this allows you to forget about HMAC, signing, nonce, ...

  • Use OAuth2:

    • When authentication requests come from my own apps/website, use this 'trick' (or a variation of it) described in a reply to the article mentioned before.

    • In my case, I have two types of users: those with classic login/password credentials and those who have signed up with Facebook Connect.
      So I'd provide a regular login form with a "Login with Facebook" button. If the user logs in with his "classic" credentials, I'd just send these to my OAuth2 endpoint with a grant_type=password.
      If he chooses to log in via Facebook, I think that would be a two-steps process:

      • First, use Facebook iOS SDK to open an FBSession
      • When that's done and the app is given back control, there should be a way to get a Facebook ID for that user. I'd send this ID alone to my OAuth2 endpoint with an extension grant understood by my server as "using an FB User ID".

Please note that I am still heavily researching on all this stuff, so that might not be a perfect answer... maybe not even a correct one! But I think that would make for a good starting point. The idea of using an "extension grant" for the Facebook authentication might involve having to register it to do things properly? I'm not quite sure.

Anyway, I hope I was able to help you even a bit, and that at least it can start a discussion to find the best solution to this problem :)

Update
The Facebook login is not a solution as pointed in the comments: anybody could send an arbitrary user ID and log in as this user on the API.

What about doing it like this:

  • Show a login form with a "Facebook login" button
  • If this login method is chosen, act kinda like the Facebook SDK: open a web page from your authentication server, which will initiate the Facebook login.
  • Once the user has logged in, Facebook will use your redirect URL to confirm; make that URL point to another endpoint of your authentication server (possibly with an extra parameter indicating the call came from an app?)
  • When the authentication endpoint is hit, the authentication can securely identify the user, retain its FB User ID/FB Session and return an access token to your app using a custom URL scheme, just like the Facebook SDK would do

Looks better?

UPDATE: see below

I've been thinking hard about this question too. It's not entirely clear to me yet but here's the route I am thinking of going. I am creating a REST API an my users only auth with Facebook connect.

On the CLIENT:

  1. Use the Facebook API to login and get an OAUTH2 code.
  2. Exchange this code for an access token.
  3. In every call to my custom API I'll include the Facebook user id and the access token.

On the API (for every method that requires user authentication):

  1. Make a request to the /me Facebook graph using the access token from above.
  2. Verify that the Facebook user id returned matches the user id passed to my API from above.
  3. If the access token has expired additional communication is required.

I have yet to test this. How does it sound?

--- Update: July 27th, 2014 to answer question ---

I only use the above exchange once upon login. Once I determine which user is logging in, I create my own access token, and that token is used from that point going forward. So the new flow looks like this...

On the CLIENT:

  1. Use the Facebook API to login and get an OAUTH2 code.
  2. Exchange this code for an access token.
  3. Request an access token from my API, including the Facebook token as a parameter

On the API

  1. Receive access token request.
  2. Make a request to the /me Facebook graph using the facebook access token
  3. Verify that the Facebook user exists and match to a user in my database
  4. Create my own access token, save it and return it to the client to be used from this point forward

This is my implementation using JWTs (JSON Web Tokens), basically similar to Chris' updated answer. I have used Facebook JS SDK and JWT.

Here's my implementation.

  1. Client: Use Facebook JS SDK to log in and get the access token.

  2. Client: Request JWT from my API by calling /verify-access-token endpoint.

  3. MyAPI: Receives access token, verify it by calling /me endpoint of Facebook API.

  4. MyAPI: If access token is valid, finds the user from database, logs in the user if exist. Create a JWT with required fields as payload, set an expiry, sign with the secret key and send back to the client.

  5. Client: Stores the JWT in local storage.

  6. Client: Sends the token (the JWT from step 5) along with the request for the next API call.

  7. MyAPI: validate the token with the secret key, if token is valid, exchange the token for a new one, send it back to the client along with the API response. (No external API calls for verification of the token here after) [if the token is invalid/expired request client to authenticate again and repeat from 1]

  8. Client Replaces the stored token with the new one and use it for the next API call. Once the token expiry is met, the token expires revoking access to API.

Every token is used once.

Read more answers about security and JWT

How secure is JWT

If you can decode JWT how are they secure?

JSON Web Tokens (JWT) as user identification and authentication tokens