Skip to content

Instantly share code, notes, and snippets.

@teamon
Created April 8, 2012 13:43
Show Gist options
  • Star 20 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save teamon/2337387 to your computer and use it in GitHub Desktop.
Save teamon/2337387 to your computer and use it in GitHub Desktop.
Play2.0 with Github OAuth2 example
package controllers
import lib._
import play.api.mvc._
import play.api.libs.json._
object Auth extends Controller {
val GITHUB = new OAuth2[GithubUser](OAuth2Settings(
"your_client_id",
"your_client_secret",
"https://github.com/login/oauth/authorize",
"https://github.com/login/oauth/access_token",
"https://api.github.com/user"
)){
def user(body: String) = Json.fromJson(Json.parse(body))
}
case class GithubUser(
login: String,
email: String,
avatar_url: String,
name: String
)
implicit def GithubUserReads: Reads[GithubUser] = new Reads[GithubUser]{
def reads(json: JsValue) =
GithubUser(
(json \ "login").as[String],
(json \ "email").as[String],
(json \ "avatar_url").as[String],
(json \ "name").as[String]
)
}
def signin() = Action { Redirect(GITHUB.signIn) }
def signout() = Action { Redirect(routes.home()).withSession() }
def callback() = Action { implicit request =>
params("code").flatMap { code =>
GITHUB.authenticate(code) map { user =>
Redirect(routes.home()).withSession("login" -> user.login)
}
} getOrElse Redirect(GITHUB.signIn)
}
protected def params[T](key: String)(implicit request: Request[T]) = request.queryString.get(key).flatMap(_.headOption)
}
import sbt._
import Keys._
import PlayProject._
object ApplicationBuild extends Build {
val appName = "my-new-app"
val appVersion = "1.0-SNAPSHOT"
val appDependencies = Seq(
"eu.teamon" %% "play-navigator" % "0.2.1-SNAPSHOT"
)
val main = PlayProject(appName, appVersion, appDependencies, mainLang = SCALA).settings(
resolvers += "teamon.eu repo" at "http://repo.teamon.eu"
)
}
package lib
import play.api.libs.ws.WS
import play.core.parsers._
case class OAuth2Settings(
clientId: String,
clientSecret: String,
signInUrl: String,
accessTokenUrl: String,
userInfoUrl: String
)
abstract class OAuth2[T](settings: OAuth2Settings){
def user(body: String): T
import settings._
lazy val signIn = signInUrl + "?client_id=" + clientId
def requestAccessToken(code: String): Option[String] = {
val resp = WS.url(accessTokenUrl +
"?client_id=" + clientId +
"&client_secret=" + clientSecret +
"&code=" + code).get.value.get.body
FormUrlEncodedParser.parse(resp).get("access_token").flatMap(_.headOption)
}
def authenticate(code: String) = requestAccessToken(code).map(requestUserInfo)
def requestUserInfo(accessToken: String): T =
user(WS.url(userInfoUrl + "?access_token=" + accessToken).get.value.get.body)
}
trait RoutesDefinition extends PlayNavigator {
val home = GET on root to Application.index
val auth = new Namespace("auth"){
val signin = GET on "signin" to Auth.signin
val signout = GET on "signout" to Auth.signout
val callback = GET on "callback" to Auth.callback
}
val assets = GET on "assets" / ** to { s: String => Assets.at(path="/public", s) }
}
@benjamincanac
Copy link

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment