API REST pour site Web qui utilise Facebook pour l'authentification

86

Nous avons un site Web où le seul moyen de vous connecter et de vous authentifier avec le site est avec Facebook (ce n'était pas mon choix). La première fois que vous vous connectez avec Facebook, un compte est automatiquement créé pour vous.

Nous voulons maintenant créer une application iPhone pour notre site et également une API publique pour que d'autres puissent utiliser notre service.

Cette question concerne la manière de s'authentifier auprès de notre site Web depuis l'application / l'API et est divisée en 2 parties:

  1. Quelle est la bonne façon de gérer l'authentification REST d'une API vers un site Web qui utilise uniquement Facebook OAuth comme méthode d'authentification?

    J'ai beaucoup lu et fait de nombreuses recherches sur les méthodes standard d'authentification pour l'API REST. Nous ne pouvons pas utiliser des méthodes telles que l' authentification de base sur HTTPS , car il n'y a pas d'informations d'identification pour un utilisateur en tant que tel. Quelque chose comme cela semble être uniquement pour authentifier les applications à l'aide de l'API.

    Actuellement, la meilleure façon de penser est que vous atteignez un point final / autoriser sur notre API, qu'il redirige vers Facebook OAuth, puis redirige vers le site et fournit un `` jeton '' que l'utilisateur de l'API peut utiliser pour s'authentifier ultérieurement. demandes.

  2. Pour une application officielle que nous créons, nous n'aurions pas nécessairement besoin d'utiliser l'API publique de la même manière. Quelle serait alors la meilleure façon de parler à notre site Web et d'authentifier les utilisateurs?

Je comprends (je pense) comment authentifier les applications tierces qui utilisent notre API, en utilisant des clés API (publiques) et des clés secrètes (privées). Cependant, quand il s'agit d'authentifier l'utilisateur qui utilise l'application, je ne sais pas trop comment s'y prendre alors que le seul moyen d'authentifier un utilisateur est Facebook.

J'ai l'impression de manquer quelque chose de très évident ou de ne pas comprendre pleinement comment les API REST publiques devraient fonctionner, donc tout conseil et aide seraient grandement appréciés.

Adam
la source
J'ai une question similaire sur stackoverflow.com/questions/30230482/… qui parle de certains d'entre eux
JVK

Réponses:

99

MISE À JOUR: voir ci-dessous

J'ai aussi beaucoup réfléchi à cette question. Ce n'est pas encore tout à fait clair pour moi, mais voici l'itinéraire que je pense emprunter. Je crée une API REST et mes utilisateurs ne s'authentifient qu'avec Facebook Connect.

Sur le CLIENT:

  1. Utilisez l'API Facebook pour vous connecter et obtenir un code OAUTH2.
  2. Échangez ce code contre un jeton d'accès.
  3. Dans chaque appel à mon API personnalisée, j'inclurai l'ID utilisateur Facebook et le jeton d'accès.

Sur l'API (pour chaque méthode nécessitant une authentification de l'utilisateur):

  1. Faites une demande au graphique Facebook / me en utilisant le jeton d'accès ci-dessus.
  2. Vérifiez que l'ID utilisateur Facebook renvoyé correspond à l'ID utilisateur transmis à mon API par le haut.
  3. Si le jeton d'accès a expiré, une communication supplémentaire est requise.

Je n'ai pas encore testé cela. Comment ça sonne?

--- Mise à jour: 27 juillet 2014 pour répondre à la question ---

Je n'utilise l'échange ci-dessus qu'une seule fois lors de la connexion. Une fois que j'ai déterminé quel utilisateur se connecte, je crée mon propre jeton d'accès, et ce jeton est utilisé à partir de ce moment. Donc, le nouveau flux ressemble à ceci ...

Sur le CLIENT:

  1. Utilisez l'API Facebook pour vous connecter et obtenir un code OAUTH2.
  2. Échangez ce code contre un jeton d'accès.
  3. Demander un jeton d'accès à mon API, y compris le jeton Facebook en tant que paramètre

Sur l'API

  1. Recevez une demande de jeton d'accès.
  2. Faites une demande au graphique Facebook / me en utilisant le jeton d'accès Facebook
  3. Vérifier que l'utilisateur Facebook existe et correspond à un utilisateur dans ma base de données
  4. Créez mon propre jeton d'accès, enregistrez-le et renvoyez-le au client pour qu'il soit utilisé à partir de ce moment
Chris Greenwood
la source
Hé, c'est un peu une réponse tardive, mais votre solution semble résoudre le problème que j'avais dans ma première réponse. Bien sûr, vous devrez utiliser HTTPS pour ne pas envoyer la paire (id, token) sur le fil en texte clair. Mais il semble que cela devrait fonctionner!
Olivier Lance
Je pense qu'il est bon de m'appeler sur le serveur et de générer votre propre jeton d'accès, qui sera utilisé par le client mobile.
Der_Meister
J'ai trouvé que stocker le secret FB dans une application mobile est une mauvaise pratique. Facebook conseille de le stocker uniquement sur votre serveur. developer.facebook.com/docs/opengraph/using-actions/…
Der_Meister
Si nous envoyons à chaque fois user_id et access_token au serveur API (comme post / get params). Cela créera-t-il une faille de sécurité si quelqu'un est capable d'intercepter la connexion?
Nathan Do
@NathanDo Utilisez HTTPS entre votre client et le serveur API et cela ne devrait pas être un problème si quelqu'un intercepte la connexion (à part les vulnérabilités de type Heartbleed).
dcr
15

Ceci est mon implémentation utilisant des JWT (jetons Web JSON), fondamentalement similaire à la réponse mise à jour de Chris. J'ai utilisé Facebook JS SDK et JWT.

Voici ma mise en œuvre.

  1. Client: utilisez Facebook JS SDK pour vous connecter et obtenir le jeton d'accès.

  2. Client: demandez JWT à mon API en appelant /verify-access-tokenendpoint.

  3. MyAPI: reçoit le jeton d'accès, vérifiez-le en appelant le /mepoint de terminaison de l'API Facebook.

  4. MyAPI: si le jeton d'accès est valide, trouve l'utilisateur dans la base de données, enregistre l'utilisateur s'il existe. Créez un JWT avec les champs obligatoires comme charge utile, définissez une expiration, signez avec la clé secrète et renvoyez-le au client.

  5. Client: stocke le JWT dans le stockage local.

  6. Client: envoie le jeton (le JWT de l'étape 5) avec la demande du prochain appel d'API.

  7. MyAPI: validez le token avec la clé secrète, si le token est valide, échangez le token contre un nouveau, renvoyez-le au client avec la réponse de l'API. (Aucun appel d'API externe pour la vérification du jeton ici après) [si le jeton est invalide / expiré, demandez au client de s'authentifier à nouveau et de répéter à partir de 1]

  8. Client Remplace le jeton stocké par le nouveau et l'utilise pour le prochain appel d'API. Une fois l'expiration du jeton atteinte, le jeton expire en révoquant l'accès à l'API.

Chaque jeton est utilisé une fois.

Lire plus de réponses sur la sécurité et JWT

Quelle est la sécurité de JWT

Si vous pouvez décoder JWT, comment sont-ils sécurisés?

Jetons Web JSON (JWT) en tant que jetons d'identification et d'authentification des utilisateurs

Tout est Vаиітy
la source
3
Je suppose que le n ° 3 devrait plutôt l'être /debug_token, vous pouvez donc vérifier que le jeton est bien pour votre application.
Peppe LG
2
Ne pas demander access_tokendans le client. Utilisez le "flux de travail de code". Passez codeà MyAPI et faites un autre aller-retour sur Facebook pour échanger codeavec access_token. Ceci est expliqué plus en détail ici: développeurs.facebook.com
docs
5

J'essaie de répondre à la même question et j'ai beaucoup lu récemment ...

Je n'aurai pas "la" réponse, mais les choses deviennent un peu plus claires pour moi. Avez-vous lu les commentaires dans l'article que vous avez mentionné ? Je les ai trouvés vraiment intéressants et utiles.

En conséquence, et à la lumière de la façon dont les choses ont évolué depuis la rédaction du premier article, voici ce que je pense que je vais faire:

  • HTTPS partout - cela vous permet d'oublier HMAC, signature, nonce, ...

  • Utilisez OAuth2:

    • Lorsque les demandes d'authentification proviennent de mes propres applications / site Web, utilisez cette «astuce» (ou une variante de celle-ci) décrite dans une réponse à l'article mentionné précédemment.

    • Dans mon cas, j'ai deux types d'utilisateurs: ceux qui ont des identifiants de connexion / mot de passe classiques et ceux qui se sont inscrits avec Facebook Connect.
      Je fournirais donc un formulaire de connexion régulier avec un bouton "Connexion avec Facebook". Si l'utilisateur se connecte avec ses informations d'identification "classiques", je les enverrais simplement à mon point de terminaison OAuth2 avec un grant_type=password.
      S'il choisit de se connecter via Facebook, je pense que ce serait un processus en deux étapes:

      • Tout d'abord, utilisez le SDK Facebook iOS pour ouvrir une session FBS
      • Lorsque cela est fait et que l'application reprend le contrôle, il devrait y avoir un moyen d'obtenir un identifiant Facebook pour cet utilisateur. J'enverrais cet ID seul à mon point de terminaison OAuth2 avec une subvention d'extension comprise par mon serveur comme «utilisant un ID utilisateur FB».

Veuillez noter que je fais encore beaucoup de recherches sur tout cela, donc ce n'est peut-être pas une réponse parfaite ... peut-être même pas la bonne! Mais je pense que cela constituerait un bon point de départ. L'idée d'utiliser une "subvention d'extension" pour l'authentification Facebook pourrait impliquer de devoir l'enregistrer pour faire les choses correctement? Je ne suis pas sûr.

Quoi qu'il en soit, j'espère avoir pu vous aider encore un peu, et qu'au moins ça pourra démarrer une discussion pour trouver la meilleure solution à ce problème :)

Mise à jour
La connexion Facebook n'est pas une solution comme indiqué dans les commentaires: n'importe qui peut envoyer un identifiant d'utilisateur arbitraire et se connecter en tant que cet utilisateur sur l'API.

Que diriez-vous de le faire comme ceci:

  • Afficher un formulaire de connexion avec un bouton "Connexion Facebook"
  • Si cette méthode de connexion est choisie, agissez un peu comme le SDK Facebook: ouvrez une page Web à partir de votre serveur d'authentification, qui lancera la connexion Facebook.
  • Une fois que l'utilisateur s'est connecté, Facebook utilisera votre URL de redirection pour confirmer; faire en sorte que cette URL pointe vers un autre point de terminaison de votre serveur d'authentification (éventuellement avec un paramètre supplémentaire indiquant que l'appel provient d'une application?)
  • Lorsque le point de terminaison d'authentification est atteint, l'authentification peut identifier en toute sécurité l'utilisateur, conserver son ID utilisateur FB / Session FB et renvoyer un jeton d'accès à votre application à l'aide d'un schéma d'URL personnalisé, comme le ferait le SDK Facebook.

Regarde mieux?

Olivier Lance
la source
1
Merci pour votre réponse! J'avais réfléchi à la plupart de ce que vous avez dit, mais la principale préoccupation que j'avais avec l'utilisation du SDK iOS FB, puis l'envoi de l'ID utilisateur Facebook était qu'il ne serait pas facile d'envoyer n'importe quel ID que vous voulez à votre point de terminaison API et prétendre être un autre utilisateur? C'est là que je finis généralement par rester coincé ..
Adam
En effet! C'était stupide de ma part de ne pas penser à ça ... Donc la solution doit passer par votre propre serveur d'authentification en quelque sorte ...
Olivier Lance
J'ai mis à jour ma réponse avec une autre idée de solution ... mais je viens de réaliser que vous l'aviez mentionnée dans votre question initiale! Je ne vois rien d'autre pour le moment ...
Olivier Lance