playframework / playframework/play-ws

OAuth remote request failure due to missing content length

Open
#211 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

status:backlog
Dominant language
Scala
Stars
224
Forks
92
Avg merge
1d 19h
Merged PRs (30d)
28

Description

Hello!

The OAuth implementation/wrapper provided with Play WS fails when a request for a token is made (i.e., the first step in the OAuth handshake). The remote server (Evernote in this case) returns a content length missing error. Details below.

Play WS Version

The version bundled with Play 2.6.10 (looks like 1.1.3 based on this).

API

Scala

Operating System

macOS/OS X 10.11.3 (El Capitan)

JDK
java version "1.8.0_92"
Java(TM) SE Runtime Environment (build 1.8.0_92-b14)
Java HotSpot(TM) 64-Bit Server VM (build 25.92-b14, mixed mode)
Library Dependencies

N/A

Expected Behavior
  1. Create an OAuth object, then callOAuth#retrieveRequestToken(callbackURL: String).
  2. Method performs a request to remote OAuth server and returns an Either[OAuthException, RequestToken] containing the result or an exception.
  3. Assuming the OAuth parameters are correct, the Either should contain a valid RequestToken.
  4. The token itself is extracted from the RequestToken object to be used in subsequent steps of the OAuth handshake.
Actual Behavior
  1. Create an OAuth object, then callOAuth#retrieveRequestToken(callbackURL: String).
  2. Method returns an Either[OAuthException, RequestToken].
  3. The OAuth parameters are correct, yet the Either contains an OAuthException: OAuthCommunicationException: Communication with the service provider failed: Service provider responded in error: 411 (Length Required).

After some research, I was able to determine that this issue is quite common with OAuth 1.0 implementations (examples: 1, 2).

The suggested fix is to include a Content-Length header set to 0 with the HTTP POST to the remote OAuth endpoint. An even better approach is to just perform a plain GET request instead.

However, Play WS does not provide a way to pass in arbitrary HTTP headers along with the request. Also, at a glance, it seems like Signpost does not provide this option either.

Reproducible Test Case
package controllers

import javax.inject.Inject

import play.api.libs.oauth._
import play.api.mvc._

class EvernoteAuthController @Inject() (cc: ControllerComponents) extends AbstractController(cc) {
  val KEY = ConsumerKey("YOUR_KEY", "YOUR_SECRET")

  val EVERNOTE = OAuth(
    ServiceInfo(
      "https://sandbox.evernote.com/oauth",
      "https://sandbox.evernote.com/oauth",
      "https://sandbox.evernote.com/OAuth.action",
      key = KEY
    ),

    use10a = false
  )

  val CALLBACK_URL = "http://localhost:9000/auth"

  def authenticate = Action { request: RequestHeader =>
    // Step 1: Request temporary token
    EVERNOTE.retrieveRequestToken(CALLBACK_URL) match {
      case Right(t: RequestToken) =>
        // Step 2: Request user authorization; pass temporary token from Step 1
        // Also, store temporary token and secret for later use
        Redirect(EVERNOTE.redirectUrl(t.token)).withSession("token" -> t.token, "secret" -> t.secret)

      // TODO: check this out!
      case Left(e) => throw e
    }
  }
}

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start at OAuth#retrieveRequestToken and trace how the token request is constructed and sent through Play WS. Reproduce the Evernote case from the issue's Scala example, then verify the request supplies the required zero Content-Length or otherwise avoids the 411 response and returns a RequestToken.

Written by the indexing model from the issue text.

Assessment

Tech stack
scala
Domain
authentication
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.