solettaproject / soletta

Soletta Project is a framework for making IoT devices. With Soletta Project's libraries developers can easily write software for devices that control actuators/sensors and communicate using standard technologies. It enables adding smartness even on the smallest edge devices.
http://solettaproject.org
Apache License 2.0
225 stars 108 forks source link

OAuth node with realistic sample #731

Open barbieri opened 9 years ago

barbieri commented 9 years ago

Rationale

Provide OAuth node types, demonstrate its usage with a realistic sample using Twitter (v1.0) and Facebook (v2).

Sadly the two versions are different and major services use one of them, such as Twitter that uses v1.0 and Facebook that uses v2.

OAuth Work Flow

V1:

Using Twitter's API (https://dev.twitter.com/web/sign-in/implementing, replacing /oauth/authenticate with /oauth/authorize as per https://dev.twitter.com/oauth/3-legged).

  1. Step 1: Obtaining a request token: POST /oauth/request_token with oauth_callback set to device IP address and some node-internal path (ie: http://device-ip/namespace/oauth_callback). Receive the temporary oauth_token and oauth_token_secret. Likely this is started by user accessing the device web server using his desktop/mobile web browser, at say http://device-ip/namespace/oauth_start. The HTTP request handler on the device web server is asynchronous and will delay the response while it finishes the POST request. After the POST is finished, the device web server answers the desktop/mobile web browser request with a 302 - Redirect to https://api.twitter.com/oauth/authorize?oauth_token=....
  2. Step 2: Redirecting the user to OAuth Service Login: as per step 1, the user should use his desktop/mobile web browser to login to the service and authorize the device application (client) to use on his behalf. Once the user finishes this process at the OAuth service provider web server, it will be redirected to the oauth_callback specified before, that points to the http://device-ip/namespace/oauth_callback as per step 1. The device web server will parse the result, upon success it will convert the temporary token into a long-lived access token using the received oauth_verifier. On failure the user will be 302 - Redirect to a device web page to show the error (finish_uri node option).
  3. Step 3: Converting the request token to an access token: as per step 2, if a valid token is received, it must be converted into a long-lived access token via POST /oauth/access_token with oauth_verifier. The response is an access token and a secret. On both success or failure the user is 302 - Redirect to finish_uri with an URI fragment indicating the current status (success or error). On success, the token string is sent on node's TOKEN output port. On failure the error is sent on node's ERROR output port.

    V2:

Using Facebook's API (https://developers.facebook.com/docs/facebook-login/manually-build-a-login-flow):

  1. Step 1: Redirecting the user to OAuth Service Login: The user access the device web server using his desktop/mobile web browser, at say http://device-ip/namespace/oauth_start. The device web server will issue a 302 - Redirect to OAuth Service Login page such as https://www.facebook.com/dialog/oauth?client_id=XXX&response_type=token&redirect_uri=http://device-ip/namespace/oauth_callback. The user should use his desktop/mobile web browser to login to the service and authorize the device application (client) to use on his behalf. Once the user finishes this process at the OAuth service provider web server, it will be redirected to the redirect_uri specified before, that points to the http://device-ip/namespace/oauth_callback. The device web server will parse the result, upon success it use the received access_token. On failure the user will be 302 - Redirect to a device web page to show the error (finish_uri node option).
  2. Step 2: (Optional) Facebook token validation: since the token above is returned as URI fragment, it's visible and may be modified. Then Facebook recommends one to validate it using its token inspection (https://developers.facebook.com/docs/facebook-login/manually-build-a-login-flow#checktoken). This is done by using an external server (ie: your product server) with a secret and private access_token. That server should do a GET graph.facebook.com/debug_token?input_token=.... If the token is valid, then it's sent on node's TOKEN output port, otherwise error is sent on node's ERROR output port.

    Suggested Node Type

    V1:

    • Options:
    • client_id (string, required): the client identifier.
    • namespace (string, required): namespace to use to allow multiple services, such as /oauth/twitter and /oauth/facebook.
    • temporary_endpoint_uri (string, required): where to get the temporary request token.
    • authorization_endpoint_uri (string, required): where to redirect user to login and then callback our app.
    • access_token_url (string, required): where to get the access token given the token verifier.
    • finish_uri (string, required): after the process is finished, then redirect to this URI providing status as URI fragment. This should show the user the result of the operation.
    • Output Ports:
    • TOKEN (string): the access token to use (it's actually a set of URL form-encoded parameters from oauth)

      V2:

    • Options:
    • client_id (string, required): the client identifier.
    • namespace (string, required): namespace to use to allow multiple services, such as /oauth/twitter and /oauth/facebook.
    • authorization_endpoint_uri (string, required): where to redirect user to login and then callback to our app.
    • validation_endpoint_uri (string, optional): server to reach with access token in order to validate it against spoof.
    • finish_uri (string, required): after the process is finished, then redirect to this URI providing status as URI fragment. This should show the user the result of the operation.
    • scope (string, optional): the scope to request authorization for.
    • Output Ports:
    • TOKEN (string): the access token to use.

      Sample FBP

fb_oauth(oauth/v2:client_id=xxx,namespace="/oauth/facebook",authorization_endpoint_uri="https://www.facebook.com/dialog/oauth",validation_endpoint_uri="https://my-server.com/oauth-verify-token/facebook",finish_uri="/facebook-oauth.html")
fb_oauth_token_persistence(persistence/string:name="fb.oauth.token",storage="efivars")
fb_updater(facebook/status-update)
needs_fb_oauth(http-server/boolean:path="needs-fb-oauth")

fb_oauth TOKEN -> IN fb_oauth_token_persistence
fb_oauth_token_persistence OUT -> OAUTH_TOKEN fb_updater
fb_oauth_token_persistence OUT -> IN (string/is-empty) OUT -> IN needs_fb_oauth
some_content_provider OUT -> MESSAGE fb_updater

Test is to ask user to visit http://device-ip, this should contain a static HTML provided by the product with its UI/theme that will query http://device-ip/needs-fb-oauth (node option), if it's true, then it will show a facebook login button. Click that button and it will go to http://device-ip/oauth/facebook/oauth_start (based on node option). User will be then redirected to Facebook's website. Once the OAuth process finishes, that website will redirect user to http://device-ip/oauth/facebook/oauth_callback that will process the results and emit the packet on output port TOKENor ERROR, then redirect to http://device-ip/facebook-oauth.html (node option), a static HTML that will get the URI fragment with a success/error and show to the user using the product UI/theme.

If the UI shows success, then user may trigger an action that creates a message to be posted to facebook.

The method for users to find out device-ip is beyond the scope of this task. Users may use avahi (zeroconf/mDNS), OIC or even assume a known IPv6 address using device's macaddress that can be encoded in QRCode to be scanned in the product enclosure.

Resources:

bdilly commented 8 years ago

v1 done by @ceolin https://github.com/solettaproject/soletta/pull/1005 https://github.com/solettaproject/soletta/pull/1052

bdilly commented 8 years ago

todo is oauth v2 using facebook as use case