Skip to content

Instantly share code, notes, and snippets.

@pulse00
Last active November 4, 2021 10:19

Revisions

  1. pulse00 revised this gist Feb 18, 2014. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion OAuthActor.scala
    Original file line number Diff line number Diff line change
    @@ -1,4 +1,4 @@
    package com.dubture.actors.github
    package com.example.actors.github

    import akka.actor.{ActorLogging, ActorRef, Actor}
    import scala.util.{Failure, Success}
  2. pulse00 created this gist Feb 18, 2014.
    18 changes: 18 additions & 0 deletions GithubJsonProtocol.scala
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,18 @@
    package com.example.actors.github

    import spray.httpx.Json4sSupport
    import org.json4s.{DefaultFormats, Formats}

    /**
    * Marshalling/Unmarshalling for the github json format
    *
    * see http://developer.github.com/v3/oauth/#web-application-flow
    */
    object GithubJsonProtocol extends Json4sSupport {

    override implicit def json4sFormats: Formats = DefaultFormats

    case class TokenRequest(client_id: String, client_secret: String, code: String, redirect_uri: String)
    case class GithubApiResult(access_token: String, scope: String, token_type: String)

    }
    72 changes: 72 additions & 0 deletions OAuthActor.scala
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,72 @@
    package com.dubture.actors.github

    import akka.actor.{ActorLogging, ActorRef, Actor}
    import scala.util.{Failure, Success}
    import spray.client.pipelining._
    import scala.concurrent.Future
    import spray.http.{HttpResponse, HttpRequest}
    import com.dubture.actors.github.OAuthActor.{TokenRetrieved, ExchangeToken}

    // marshaller/unmarshaller implicits for the pipeline
    import GithubJsonProtocol._

    /**
    * Companion object defines messages retrieved/sent by this actor.
    */
    object OAuthActor {
    case class ExchangeToken(code: String)
    case class TokenRetrieved(token: String)
    }


    /**
    * Retrieve an oauth token from the github API v3
    *
    * @param clientId
    * @param clientSecret
    * @param redirectUri
    */
    class OAuthActor(clientId: String, clientSecret: String, redirectUri: String) extends Actor with ActorLogging {

    val accessTokenUri = "https://github.com/login/oauth/access_token"

    /**
    * Fire an HTTP POST request to the github API to exchange an oauth code against a persistent token
    *
    * @param requestor
    * @param code
    */
    def retrieveTokenFromCode(requestor: ActorRef, code: String) = {

    // execution context for the future
    import context.dispatcher

    // setup request/response logging
    val logRequest: HttpRequest => HttpRequest = { r => log.debug(r.toString); r }
    val logResponse: HttpResponse => HttpResponse = { r => log.debug(r.toString); r }

    val pipeline = (
    // we want to get json
    addHeader("Accept", "application/json")
    ~> logRequest
    // if this shows a compilation error in IntelliJ, it is just a bug in the IDE - it compiles fine
    ~> sendReceive
    ~> logResponse
    ~> unmarshal[GithubApiResult]
    )

    // get the future
    val response: Future[GithubApiResult] = pipeline { Post(accessTokenUri, TokenRequest(clientId, clientSecret, code, redirectUri)) }

    // handle result/failure
    response.onComplete {
    case Success(response: GithubApiResult) => requestor ! TokenRetrieved(response.access_token)
    case Failure(e) => requestor ! Failure(e)
    }
    }

    override def receive = {
    case ExchangeToken(code) => retrieveTokenFromCode(sender, code)
    }

    }