ApplicationSpec.scala 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536
  1. import play.api.test.Helpers._
  2. import play.api.test.{FakeRequest,WithApplication}
  3. import play.api.mvc.{Results,Headers}
  4. import play.api.libs.json.{JsObject,Json}
  5. import org.scalatest.BeforeAndAfterAll
  6. import org.scalatest.tagobjects.Slow
  7. import org.scalatestplus.play._
  8. import org.scalatestplus.play.guice.GuiceOneServerPerSuite
  9. import com.weEat.shared.models.{User,UserAuthorization}
  10. import scala.concurrent.duration._
  11. import java.util.Base64
  12. class OAuthSpec extends PlaySpec
  13. with BeforeAndAfterAll
  14. with Results
  15. with GuiceOneServerPerSuite {
  16. val email = "tuser@sample.org"
  17. val password = "password"
  18. val fname = "test"
  19. val lname = "user"
  20. val users = Seq(
  21. (User("test", "user", "tuser@sample.org"), "password"),
  22. (User("another", "user", "usert@sample.org"), "password")
  23. )
  24. implicit class CSRFWrapper[T](requ: FakeRequest[T]) {
  25. def withCSRFToken() = requ.withHeaders(
  26. requ.headers.add(("Csrf-Token", "nocheck"))
  27. )
  28. }
  29. def makeAuthHeader(username: String, password: String) =
  30. Headers(("Authorization" -> s"Basic ${new String(Base64.getEncoder.encode(s"$username:$password".getBytes))}"))
  31. def makeAuthHeader(auth: UserAuthorization) =
  32. Headers(("Authorization" -> s"${auth.tokenType} ${auth.accessToken}"))
  33. override def beforeAll() = {
  34. for ((User(fname, lname, email), password) <- users) {
  35. val Some(resp) = route(app, FakeRequest(PUT, "/user/").withJsonBody(
  36. Json.parse(s"""|{
  37. | "fname": "$fname",
  38. | "lname": "$lname",
  39. | "email": "$email",
  40. | "password": "$password"
  41. |}""".stripMargin)
  42. ).withCSRFToken())
  43. status(resp) mustEqual OK
  44. }
  45. }
  46. "the token endpoint" should {
  47. "reject an empty request" in {
  48. val Some(resp) = route(app, FakeRequest(POST, "/authorize/")
  49. .withHeaders(makeAuthHeader(users(0)._1.email, users(0)._2))
  50. .withCSRFToken()
  51. )
  52. status(resp) mustEqual BAD_REQUEST
  53. headers(resp) must contain ("WWW-Authenticate" ->
  54. ("Bearer error=\"invalid_request\", "+
  55. "error_description=\"required parameter: grant_type\"")
  56. )
  57. }
  58. "reject an improperly formatted request" in {
  59. val Some(resp) = route(app, FakeRequest(POST, "/authorize/")
  60. .withBody("""{"grant_type" "password"}""")
  61. .withHeaders(
  62. makeAuthHeader(email, password).add(("Content-Type", "application/json"))
  63. ).withCSRFToken()
  64. )
  65. status(resp) mustEqual BAD_REQUEST
  66. // Won't get an OAuth response header. Will fail before processing.
  67. }
  68. "reject a missing grant_type" in {
  69. val Some(resp) = route(app, FakeRequest(POST, "/authorize/")
  70. .withJsonBody(Json.parse("{}"))
  71. .withHeaders(makeAuthHeader(users(0)._1.email, users(0)._2))
  72. .withCSRFToken()
  73. )
  74. status(resp) mustEqual BAD_REQUEST
  75. headers(resp) must contain ("WWW-Authenticate" ->
  76. ("Bearer error=\"invalid_request\", "+
  77. "error_description=\"required parameter: grant_type\"")
  78. )
  79. }
  80. }
  81. "the token endpoint for password grants" should {
  82. "accept a valid login" in {
  83. val Some(resp) = route(app, FakeRequest(POST, "/authorize/")
  84. .withJsonBody(Json.parse("""{"grant_type": "password"}"""))
  85. .withHeaders(makeAuthHeader(users(0)._1.email, users(0)._2))
  86. .withCSRFToken()
  87. )
  88. status(resp) mustEqual OK
  89. contentAsJson(resp).as[UserAuthorization] must matchPattern {
  90. case UserAuthorization(_, _, _, _) =>
  91. }
  92. }
  93. "issue unique access tokens for successive logins" in {
  94. val requ = FakeRequest(POST, "/authorize/")
  95. .withJsonBody(Json.parse("""{"grant_type": "password"}"""))
  96. .withHeaders(makeAuthHeader(users(0)._1.email, users(0)._2))
  97. .withCSRFToken()
  98. val Some(resp1) = route(app, requ)
  99. val Some(resp2) = route(app, requ)
  100. status(resp2) mustEqual OK
  101. val resp1Auth = contentAsJson(resp1).as[UserAuthorization]
  102. val resp2Auth = contentAsJson(resp2).as[UserAuthorization]
  103. resp1Auth must matchPattern {
  104. case UserAuthorization(_, _, _, _) =>
  105. }
  106. resp2Auth must matchPattern {
  107. case UserAuthorization(_, _, _, _) =>
  108. }
  109. resp1Auth.accessToken mustNot equal(resp2Auth.accessToken)
  110. resp1Auth.refreshToken mustNot equal(resp2Auth.refreshToken)
  111. }
  112. "reject an unregistered user" in {
  113. val Some(resp) = route(app, FakeRequest(POST, "/authorize/")
  114. .withJsonBody(Json.parse("""{"grant_type": "password"}"""))
  115. .withHeaders(makeAuthHeader(
  116. "_"+users(0)._1.email,
  117. "_"+users(0)._2
  118. ))
  119. .withCSRFToken()
  120. )
  121. status(resp) mustEqual UNAUTHORIZED
  122. headers(resp) must contain ("WWW-Authenticate" ->
  123. ("Bearer error=\"invalid_client\", "+
  124. "error_description=\"Invalid client or client is not authorized\""))
  125. }
  126. "reject an incorrect password" in {
  127. val Some(resp) = route(app, FakeRequest(POST, "/authorize/")
  128. .withJsonBody(Json.parse("""{"grant_type": "password"}"""))
  129. .withHeaders(makeAuthHeader(users(0)._1.email, "_"+users(0)._2))
  130. .withCSRFToken()
  131. )
  132. status(resp) mustEqual UNAUTHORIZED
  133. headers(resp) must contain ("WWW-Authenticate" ->
  134. ("Bearer error=\"invalid_client\", "+
  135. "error_description=\"Invalid client or client is not authorized\"")
  136. )
  137. }
  138. "reject an incorrect username" in {
  139. val Some(resp) = route(app, FakeRequest(POST, "/authorize/")
  140. .withJsonBody(Json.parse("""{"grant_type": "password"}"""))
  141. .withHeaders(makeAuthHeader("_"+users(0)._1.email, users(0)._2))
  142. .withCSRFToken()
  143. )
  144. status(resp) mustEqual UNAUTHORIZED
  145. headers(resp) must contain ("WWW-Authenticate" ->
  146. ("Bearer error=\"invalid_client\", "+
  147. "error_description=\"Invalid client or client is not authorized\"")
  148. )
  149. }
  150. "reject an requests without Authorization headers" in {
  151. val Some(resp) = route(app, FakeRequest(POST, "/authorize/")
  152. .withJsonBody(Json.parse(s"""{"grant_type": "password"}""")
  153. ).withCSRFToken())
  154. status(resp) mustEqual BAD_REQUEST
  155. headers(resp) must contain ("WWW-Authenticate" ->
  156. ("Bearer error=\"invalid_request\", "+
  157. "error_description=\"Client credential is not found\"")
  158. )
  159. }
  160. }
  161. "the token endpoint for refresh grants" should {
  162. "accept a given refresh token" in {
  163. val auth = contentAsJson(route(app, FakeRequest(POST, "/authorize/")
  164. .withJsonBody(Json.parse("""{"grant_type": "password"}"""))
  165. .withHeaders(makeAuthHeader(users(0)._1.email, users(0)._2))
  166. .withCSRFToken()
  167. ).get).as[UserAuthorization]
  168. val Some(resp) = route(app, FakeRequest(POST, "/authorize/")
  169. .withJsonBody(Json.parse(s"""|{
  170. | "grant_type": "refresh_token",
  171. | "client_id": "${users(0)._1.email}",
  172. | "refresh_token": "${auth.refreshToken}"
  173. |}""".stripMargin))
  174. .withCSRFToken()
  175. )
  176. status(resp) mustEqual OK
  177. val newAuth = contentAsJson(resp).as[UserAuthorization]
  178. newAuth must matchPattern {
  179. case UserAuthorization(_, _, _, _) =>
  180. }
  181. newAuth.accessToken mustNot equal(auth.accessToken)
  182. newAuth.refreshToken mustNot equal(auth.refreshToken)
  183. }
  184. "reject a given refresh token on the second attempt" in {
  185. val auth = contentAsJson(route(app, FakeRequest(POST, "/authorize/")
  186. .withJsonBody(Json.parse("""{"grant_type": "password"}"""))
  187. .withHeaders(makeAuthHeader(users(0)._1.email, users(0)._2))
  188. .withCSRFToken()
  189. ).get).as[UserAuthorization]
  190. val Some(resp1) = route(app, FakeRequest(POST, "/authorize/")
  191. .withJsonBody(Json.parse(s"""|{
  192. | "grant_type": "refresh_token",
  193. | "client_id": "${users(0)._1.email}",
  194. | "refresh_token": "${auth.refreshToken}"
  195. |}""".stripMargin))
  196. .withCSRFToken()
  197. )
  198. status(resp1) mustEqual OK
  199. contentAsJson(resp1).as[UserAuthorization] must matchPattern {
  200. case UserAuthorization(_, _, _, _) =>
  201. }
  202. val Some(resp2) = route(app, FakeRequest(POST, "/authorize/")
  203. .withJsonBody(Json.parse(s"""|{
  204. | "grant_type": "refresh_token",
  205. | "client_id": "${users(0)._1.email}",
  206. | "refresh_token": "${auth.refreshToken}"
  207. |}""".stripMargin))
  208. .withCSRFToken()
  209. )
  210. status(resp2) mustEqual UNAUTHORIZED
  211. headers(resp2) must contain ("WWW-Authenticate" ->
  212. ("Bearer error=\"invalid_client\", "+
  213. "error_description=\"Invalid client or client is not authorized\"")
  214. )
  215. }
  216. "reject a revoked refresh token" in {
  217. val auth = contentAsJson(route(app, FakeRequest(POST, "/authorize/")
  218. .withJsonBody(Json.parse("""{"grant_type": "password"}"""))
  219. .withHeaders(makeAuthHeader(users(0)._1.email, users(0)._2))
  220. .withCSRFToken()
  221. ).get).as[UserAuthorization]
  222. val Some(resp1) = route(app, FakeRequest(DELETE, "/authorize/")
  223. .withJsonBody(Json.parse(s"""|{
  224. | "grant_type": "refresh_token",
  225. | "client_id": "${users(0)._1.email}",
  226. | "refresh_token": "${auth.refreshToken}"
  227. |}""".stripMargin))
  228. .withHeaders(makeAuthHeader(auth))
  229. .withCSRFToken()
  230. )
  231. status(resp1) mustEqual OK
  232. val Some(resp2) = route(app, FakeRequest(POST, "/authorize/")
  233. .withJsonBody(Json.parse(s"""|{
  234. | "grant_type": "refresh_token",
  235. | "client_id": "${users(0)._1.email}",
  236. | "refresh_token": "${auth.refreshToken}"
  237. |}""".stripMargin))
  238. .withCSRFToken()
  239. )
  240. status(resp2) mustEqual UNAUTHORIZED
  241. headers(resp2) must contain ("WWW-Authenticate" ->
  242. ("Bearer error=\"invalid_client\", "+
  243. "error_description=\"Invalid client or client is not authorized\"")
  244. )
  245. }
  246. "reject a given refresh token with an incorrect username" in {
  247. val auth = contentAsJson(route(app, FakeRequest(POST, "/authorize/")
  248. .withJsonBody(Json.parse("""{"grant_type": "password"}"""))
  249. .withHeaders(makeAuthHeader(users(0)._1.email, users(0)._2))
  250. .withCSRFToken()
  251. ).get).as[UserAuthorization]
  252. val Some(resp) = route(app, FakeRequest(POST, "/authorize/")
  253. .withJsonBody(Json.parse(s"""|{
  254. | "grant_type": "refresh_token",
  255. | "client_id": "_${users(0)._1.email}",
  256. | "refresh_token": "${auth.refreshToken}"
  257. |}""".stripMargin))
  258. .withCSRFToken()
  259. )
  260. status(resp) mustEqual UNAUTHORIZED
  261. headers(resp) must contain ("WWW-Authenticate" ->
  262. ("Bearer error=\"invalid_client\", "+
  263. "error_description=\"Invalid client or client is not authorized\"")
  264. )
  265. }
  266. "reject an unprovided refresh token" in {
  267. val auth = contentAsJson(route(app, FakeRequest(POST, "/authorize/")
  268. .withJsonBody(Json.parse("""{"grant_type": "password"}"""))
  269. .withHeaders(makeAuthHeader(users(0)._1.email, users(0)._2))
  270. .withCSRFToken()
  271. ).get).as[UserAuthorization]
  272. val fakeToken = (auth.refreshToken.charAt(0)+1) +
  273. auth.refreshToken.substring(1);
  274. val Some(resp) = route(app, FakeRequest(POST, "/authorize/")
  275. .withJsonBody(Json.parse(s"""|{
  276. | "grant_type": "refresh_token",
  277. | "client_id": "${users(0)._1.email}",
  278. | "refresh_token": "$fakeToken"
  279. |}""".stripMargin))
  280. .withCSRFToken()
  281. )
  282. status(resp) mustEqual UNAUTHORIZED
  283. headers(resp) must contain ("WWW-Authenticate" ->
  284. ("Bearer error=\"invalid_client\", "+
  285. "error_description=\"Invalid client or client is not authorized\"")
  286. )
  287. }
  288. }
  289. "the secured endpoint" should {
  290. "accept an authorized request" in {
  291. val auth = contentAsJson(route(app, FakeRequest(POST, "/authorize/")
  292. .withJsonBody(Json.parse("""{"grant_type": "password"}"""))
  293. .withHeaders(makeAuthHeader(email, password))
  294. .withCSRFToken()
  295. ).get).as[UserAuthorization]
  296. val Some(resp) = route(app, FakeRequest(GET, "/user/self/name/")
  297. .withHeaders(makeAuthHeader(auth))
  298. .withCSRFToken()
  299. )
  300. status(resp) mustEqual OK
  301. contentAsString(resp) must
  302. equal(s"${users(0)._1.fname} ${users(0)._1.lname}")
  303. }
  304. "reject an unauthorized request" in {
  305. val Some(resp) = route(app, FakeRequest(GET, "/user/self/name/")
  306. .withCSRFToken()
  307. )
  308. status(resp) mustEqual BAD_REQUEST
  309. headers(resp) must contain ("WWW-Authenticate" ->
  310. ("Bearer error=\"invalid_request\", "+
  311. "error_description=\"Access token is not found\"")
  312. )
  313. }
  314. "reject an forged authorized request" in {
  315. val fakeToken = "7pKNy790TV5lKVjQw3k/pwJmMS8XBhHaLTVaI6ftd5M="
  316. val Some(resp) = route(app, FakeRequest(GET, "/user/self/name/")
  317. .withHeaders(("Authorization" -> s"Bearer $fakeToken"))
  318. .withCSRFToken()
  319. )
  320. status(resp) mustEqual UNAUTHORIZED
  321. headers(resp) must contain ("WWW-Authenticate" ->
  322. ("Bearer error=\"invalid_token\", "+
  323. "error_description=\"The access token is not found\"")
  324. )
  325. }
  326. "reject a refreshed access token" in {
  327. val auth = contentAsJson(route(app, FakeRequest(POST, "/authorize/")
  328. .withJsonBody(Json.parse("""{"grant_type": "password"}"""))
  329. .withHeaders(makeAuthHeader(users(0)._1.email, users(0)._2))
  330. .withCSRFToken()
  331. ).get).as[UserAuthorization]
  332. val Some(resp1) = route(app, FakeRequest(POST, "/authorize/")
  333. .withJsonBody(Json.parse(s"""|{
  334. | "grant_type": "refresh_token",
  335. | "client_id": "${users(0)._1.email}",
  336. | "refresh_token": "${auth.refreshToken}"
  337. |}""".stripMargin))
  338. .withCSRFToken()
  339. )
  340. status(resp1) mustEqual OK
  341. val Some(resp2) = route(app, FakeRequest(GET, "/user/self/name/")
  342. .withHeaders(makeAuthHeader(auth))
  343. .withCSRFToken()
  344. )
  345. status(resp2) mustEqual UNAUTHORIZED
  346. headers(resp2) must contain ("WWW-Authenticate" ->
  347. ("Bearer error=\"invalid_token\", "+
  348. "error_description=\"The access token is invalid\"")
  349. )
  350. }
  351. "reject a revoked access token" in {
  352. val auth = contentAsJson(route(app, FakeRequest(POST, "/authorize/")
  353. .withJsonBody(Json.parse("""{"grant_type": "password"}"""))
  354. .withHeaders(makeAuthHeader(users(0)._1.email, users(0)._2))
  355. .withCSRFToken()
  356. ).get).as[UserAuthorization]
  357. val Some(resp1) = route(app, FakeRequest(DELETE, "/authorize/")
  358. .withJsonBody(Json.parse(s"""|{
  359. | "grant_type": "refresh_token",
  360. | "client_id": "${users(0)._1.email}",
  361. | "refresh_token": "${auth.refreshToken}"
  362. |}""".stripMargin))
  363. .withHeaders(makeAuthHeader(auth))
  364. .withCSRFToken()
  365. )
  366. status(resp1) mustEqual OK
  367. val Some(resp2) = route(app, FakeRequest(GET, "/user/self/name/")
  368. .withHeaders(makeAuthHeader(auth))
  369. .withCSRFToken()
  370. )
  371. status(resp2) mustEqual UNAUTHORIZED
  372. headers(resp2) must contain ("WWW-Authenticate" ->
  373. ("Bearer error=\"invalid_token\", "+
  374. "error_description=\"The access token is invalid\"")
  375. )
  376. }
  377. /*
  378. "reject an expired access token" taggedAs(Slow) in {
  379. val auth = contentAsJson(route(app, FakeRequest(POST, "/authorize/")
  380. .withJsonBody(Json.parse("""{"grant_type": "password"}"""))
  381. .withHeaders(makeAuthHeader(email, password))
  382. ).get).as[UserAuthorization]
  383. Thread.sleep((1 hour).toMillis)
  384. val Some(resp) = route(app, FakeRequest(GET, "/user/self/name/")
  385. .withHeaders(makeAuthHeader(auth)))
  386. status(resp) mustEqual UNAUTHORIZED
  387. headers(resp) must contain ("WWW-Authenticate" ->
  388. ("Bearer error=\"invalid_token\", "+
  389. "error_description=\"The access token is invalid\"")
  390. )
  391. }
  392. */
  393. }
  394. "the token endpoint for revokation requests" should {
  395. "accept a valid request" in {
  396. val auth = contentAsJson(route(app, FakeRequest(POST, "/authorize/")
  397. .withJsonBody(Json.parse("""{"grant_type": "password"}"""))
  398. .withHeaders(makeAuthHeader(users(0)._1.email, users(0)._2))
  399. .withCSRFToken()
  400. ).get).as[UserAuthorization]
  401. val Some(resp) = route(app, FakeRequest(DELETE, "/authorize/")
  402. .withJsonBody(Json.parse(s"""|{
  403. | "grant_type": "refresh_token",
  404. | "client_id": "${users(0)._1.email}",
  405. | "refresh_token": "${auth.refreshToken}"
  406. |}""".stripMargin))
  407. .withHeaders(makeAuthHeader(auth))
  408. .withCSRFToken()
  409. )
  410. status(resp) mustEqual OK
  411. contentAsString(resp) mustEqual("")
  412. }
  413. "reject a request with an invalid authorization header" in {
  414. val auth = contentAsJson(route(app, FakeRequest(POST, "/authorize/")
  415. .withJsonBody(Json.parse("""{"grant_type": "password"}"""))
  416. .withHeaders(makeAuthHeader(users(0)._1.email, users(0)._2))
  417. .withCSRFToken()
  418. ).get).as[UserAuthorization]
  419. val fakeToken = (auth.accessToken.charAt(0)+1) +
  420. auth.accessToken.substring(1);
  421. val Some(resp) = route(app, FakeRequest(DELETE, "/authorize/")
  422. .withJsonBody(Json.parse(s"""|{
  423. | "grant_type": "refresh_token",
  424. | "client_id": "${users(0)._1.email}",
  425. | "refresh_token": "${auth.refreshToken}"
  426. |}""".stripMargin))
  427. .withHeaders("Authorization" -> s"Bearer $fakeToken")
  428. .withCSRFToken()
  429. )
  430. status(resp) mustEqual UNAUTHORIZED
  431. headers(resp) must contain ("WWW-Authenticate" ->
  432. ("Bearer error=\"invalid_token\", "+
  433. "error_description=\"The access token is not found\"")
  434. )
  435. }
  436. "reject a request without an authorization header" in {
  437. val auth = contentAsJson(route(app, FakeRequest(POST, "/authorize/")
  438. .withJsonBody(Json.parse("""{"grant_type": "password"}"""))
  439. .withHeaders(makeAuthHeader(users(0)._1.email, users(0)._2))
  440. .withCSRFToken()
  441. ).get).as[UserAuthorization]
  442. val Some(resp) = route(app, FakeRequest(DELETE, "/authorize/")
  443. .withJsonBody(Json.parse(s"""|{
  444. | "grant_type": "refresh_token",
  445. | "client_id": "${users(0)._1.email}",
  446. | "refresh_token": "${auth.refreshToken}"
  447. |}""".stripMargin))
  448. .withCSRFToken()
  449. )
  450. status(resp) mustEqual BAD_REQUEST
  451. headers(resp) must contain ("WWW-Authenticate" ->
  452. ("Bearer error=\"invalid_request\", "+
  453. "error_description=\"Access token is not found\"")
  454. )
  455. }
  456. "reject a request with an unissued refresh token" in {
  457. val auth = contentAsJson(route(app, FakeRequest(POST, "/authorize/")
  458. .withJsonBody(Json.parse("""{"grant_type": "password"}"""))
  459. .withHeaders(makeAuthHeader(users(0)._1.email, users(0)._2))
  460. .withCSRFToken()
  461. ).get).as[UserAuthorization]
  462. val fakeToken = (auth.refreshToken.charAt(0)+1) +
  463. auth.refreshToken.substring(1);
  464. val Some(resp) = route(app, FakeRequest(DELETE, "/authorize/")
  465. .withJsonBody(Json.parse(s"""|{
  466. | "grant_type": "refresh_token",
  467. | "client_id": "${users(0)._1.email}",
  468. | "refresh_token": "${fakeToken}"
  469. |}""".stripMargin))
  470. .withHeaders(makeAuthHeader(auth))
  471. .withCSRFToken()
  472. )
  473. status(resp) mustEqual UNAUTHORIZED
  474. headers(resp) must contain ("WWW-Authenticate" ->
  475. ("Bearer error=\"invalid_token\", "+
  476. "error_description=\"The access token is invalid\"")
  477. )
  478. }
  479. "reject a request with an incorrect username" in {
  480. val auth = contentAsJson(route(app, FakeRequest(POST, "/authorize/")
  481. .withJsonBody(Json.parse("""{"grant_type": "password"}"""))
  482. .withHeaders(makeAuthHeader(users(0)._1.email, users(0)._2))
  483. .withCSRFToken()
  484. ).get).as[UserAuthorization]
  485. val Some(resp) = route(app, FakeRequest(DELETE, "/authorize/")
  486. .withJsonBody(Json.parse(s"""|{
  487. | "grant_type": "refresh_token",
  488. | "client_id": "_${users(0)._1.email}",
  489. | "refresh_token": "${auth.refreshToken}"
  490. |}""".stripMargin))
  491. .withHeaders(makeAuthHeader(auth))
  492. .withCSRFToken()
  493. )
  494. status(resp) mustEqual UNAUTHORIZED
  495. headers(resp) must contain ("WWW-Authenticate" ->
  496. ("Bearer error=\"invalid_client\", "+
  497. "error_description=\"Invalid client or client is not authorized\"")
  498. )
  499. }
  500. }
  501. }