OAuth in Lift

435 views
Skip to first unread message

Rouzbeh

unread,
Jan 1, 2012, 6:52:00 PM1/1/12
to Lift
Hello all,

Can somebody direct me to a wiki/doc that would help me get started in
OAuth and lift - as an starting point(Something like David P's chapter
for OpenID). I see some lift-oauth/mapper archetypes in the repo, but
have no idea which is which and where to start.

Thanks allot, and happy new year.

Rouzbeh

Tobias Pfeiffer

unread,
Jan 2, 2012, 9:07:13 AM1/2/12
to lif...@googlegroups.com
Hi,

Am Montag, 2. Januar 2012, um 00:52:00 schrieb Rouzbeh:
> Can somebody direct me to a wiki/doc that would help me get started in
> OAuth and lift - as an starting point(Something like David P's chapter
> for OpenID).

Do you want to use OAuth to, e.g. authenticate your user with a 3rd party
service, or do you want to *provide* OAuth services yourself?

Tobias

David Ashirov

unread,
Jan 2, 2012, 12:17:36 PM1/2/12
to lif...@googlegroups.com

I'd love to learn how to provide the services, but I think the oauth module provided as a part of lift is a client.

On the client side, i'm struggling to understand what id_token is and whether it can be used as a primary key of some sort.

--
Lift, the simply functional web framework: http://liftweb.net
Code: http://github.com/lift
Discussion: http://groups.google.com/group/liftweb
Stuck? Help us help you: https://www.assembla.com/wiki/show/liftweb/Posting_example_code

Rouzbeh

unread,
Jan 2, 2012, 5:30:35 PM1/2/12
to Lift
I want to be a consumer of an OAuth provider (yammer), and want to
create a client app. I have read different blogs and random mail
threads and apparently the best choice is using dispatch ( if I want
to use only scala) ....

Now apparently there is a Lift client .... but cant find a wiki or
doc

http://www.assembla.com/spaces/liftweb/wiki/OAuth

I was just wondering if there is starting point like OpenId ?

Thanks,
R.

dbcfd

unread,
Jan 2, 2012, 9:27:28 PM1/2/12
to Lift
I'd also love if there was an easier way to accomplish this. Using
early response and redirect, I was able to integrate with Foursquare's
OAuth, but it's definitely not pretty, and I notice that there are
multiple redirects involved (logging when it occurs). Seems like there
should be a straightforward way to send off the oauth request and get
a callback, storing it for the session.

Tobias Pfeiffer

unread,
Jan 3, 2012, 5:54:48 AM1/3/12
to lif...@googlegroups.com
Hi,

Am Montag, 2. Januar 2012, 14:30:35 schrieb Rouzbeh:
> I want to be a consumer of an OAuth provider (yammer), and want to
> create a client app. I have read different blogs and random mail
> threads and apparently the best choice is using dispatch ( if I want
> to use only scala) ....
>
> Now apparently there is a Lift client .... but cant find a wiki or
> doc

From what I understand, this is a OAuth provider implementation (e.g. to
provide an OAuth-authenticated API), not a client (correct me if I'm wrong).

I've been using dispatch <http://dispatch.databinder.net/Dispatch.html> to
authenticate against an OAuth-enabled authentication provider like this:

1. My User model object overrides loginMenuLocParams with an EarlyResponse
LocParam that first gets a request token like

val consumer = Consumer(apikey, apisecret)
val h = new Http
val baseRequest = (:/(host, Integer.valueOf(port)))

val callback = "http://myhost.com/oauth_verify/"
val req_token = h(baseRequest / "oauth" / "request_token" <@(consumer,
callback) as_token)

then stores the request token in a SessionVar and redirects:

request_token(req_token)
val authURI = (baseRequest / "oauth" / "authorize" with_token
request_token).to_uri
Full(RedirectResponse(authURI.toString))

2. To handle visits to /oauth_verify, I added a custom dispatch function

LiftRules.dispatch.append{
case Req(List("oauth_verify", _), _, _) =>
() => User.storeOAuthInfo()
}

and in User.storeOAuthInfo(), I basically do the following:

val oauth_token = S.param("oauth_token").getOrElse("")
val oauth_verifier = S.param("oauth_verifier").getOrElse("")
// get the access token for that user:
val access_token = h(baseRequest / "oauth" / "access_token" <@
(consumer, request_token, oauth_verifier) as_token)

3. Then of course, you need some way to match your local user entry with
that remotely authenticated user, e.g. an email address, and somehow store
the OAuth tokens for that user.

4. An API call is then done like this:

val access_token = new Token(User.currentUser.get.access_token_value,
User.currentUser.get.access_token_secret)
val req = restRequest <<? Map("method" -> "method.name",
"param" -> "42",
"format" -> "xml") <@ (consumer,
access_token,
User.currentUser.get.verification_code)

Hope this helps,
Tobias

signature.asc

bg

unread,
Nov 3, 2012, 6:48:14 PM11/3/12
to lif...@googlegroups.com
Hi,

I'm trying to following this example to consume an OAuth service, but am getting a compile error  "not found: value Consumer"

SBT dependency

"net.databinder.dispatch" %% "dispatch-core" % "0.9.3"
 

code 


import dispatch._
import oauth._
//import OAuth._  <-- this import fails

class oAuth {
  //val consumer = com.ning.http.client.oauth.ConsumerKey(apikey, apisecret)
  val consumer = Consumer("[seekrit!]", "[also seekrit!]")
  val h = new Http

...


Is it from an older version of dispatch, so an updated way to call this is needed? Or am I missing an SBT dependancy? (or other)

Diego Medina

unread,
Nov 3, 2012, 9:08:08 PM11/3/12
to lif...@googlegroups.com

I think that the 0.9 version has a very different api, you can try a version from 0.8.x

That should work well

Diego
Sent from my android cell

--

bg

unread,
Nov 7, 2012, 8:51:09 AM11/7/12
to lif...@googlegroups.com
Great thanks for that - using a v8 library resolved it.

I am trying to work with Linked in OAuth, and would like to use it to log in my user. To do this I would like Linked In to provide an email address, and based on https://developer.linkedin.com/documents/connections-api I believe that means I need to make my request include "scope=r_basicprofile+r_emailaddress"

Looking at package dispatch.oauth there is a user_params: Map[String, Any] variable, but I am unsure how to set it. My code currently looks like

 def LinkedInOAuth() = {
   //(key: String, secret: String)
   val consumer = Consumer("dfsgdfg", "sdfgsdfgdf")
   val h = new Http
   val baseRequest = (:/("api.linkedin.com") / "uas").secure
   val callback = "user"

 

   val req_token = h(baseRequest / "oauth" / "requestToken" <@ (consumer,
     callback) as_token)  <-- think I need to set a custom parameter in this request to include "scope=r_basicprofile+r_emailaddress"

   //request_token(req_token)
    val authURI = (baseRequest / "oauth" / "authorize" with_token req_token).to_uri
   println(authURI)

   println("Please enter your oauth_token code")
   //val oauth_token = S.param("oauth_token").getOrElse("")
   val oauth_token = Console.readLine()



Another point is the LinkedIn docs say they are expecting Posts, but my console output is telling me I'm doing Gets. Have I got something else wrong?

Denis Bardadym

unread,
Nov 7, 2012, 9:56:27 AM11/7/12
to lif...@googlegroups.com
Hello.

We also doing linkedin oauth integration using dispatch library.

For linkedin i used such Auth object:

object Auth {
  val svc = :/("api.linkedin.com") / "uas" / "oauth"
  val svcAuth = :/("www.linkedin.com")/"uas"/"oauth"/"authenticate"

  def request_token(consumer: Consumer, callback_url: String) =
    svc.secure.POST / "requestToken" <@ (consumer, callback_url) as_token

  def request_token(consumer: Consumer, callback_url: String, permissions: List[String]) =
    svc.secure.POST / "requestToken" <<? (("scope", permissions.mkString(",")) :: Nil) <@ (consumer, callback_url) as_token

  def authenticate_url(token: Token) =
    svcAuth.secure with_token token

  def access_token(consumer: Consumer, token: Token, verifier: String) =
    svc.secure.POST / "accessToken" <@ (consumer, token, verifier) >% {
      m => Token(m).get
    }

  def access_token(consumer: Consumer, token: String) =
    svc.secure.POST / "accessToken" <<? (("xoauth_oauth2_access_token", token) :: Nil) <@ (consumer) >% {
      m => Token(m).get
    }
}

Then to login need to do such steps:

1. First request a request token from linkedin. It should be something like this:
val requestToken = http(Auth.request_token(consumer, callbackUrl, LinkedInAPI.defaultPermissions))
Then save it in session, to check when user goes to callbackUrl.
2. Redirect user to authorization url:
Auth.authenticate_url(requestToken).to_uri.toString)

Next on callback dispatcher:
3. Check that requestToken in session and oauth_verifier param in url.
4. Ask linked in about access_token
val accessToken = http(Auth.access_token(consumer, requestToken, oauth_verifier))
Now save it and use to do linked in calls from this user.

All this about dispatch 0.8.8, others not tested.

Denis.

среда, 7 ноября 2012 г. в 17:51, bg написал:

bg

unread,
Nov 8, 2012, 6:21:02 AM11/8/12
to lif...@googlegroups.com
Hi Denis - thanks for sharing that code, it helped me clean up my implementation

One thing I'm not clear on still after reading the linked in docs and looking at the logs is, does obtaining the authenticate_url involve a new request to Linked In apis?

To try make the question clearer, I can see the below logging from dispatch

[console logger] dispatch: api.linkedin.com POST /uas/oauth/requestToken?scope=r_basicprofile%2Cr_emailaddress HTTP/1.1
[console logger] dispatch: api.linkedin.com POST /uas/oauth/accessToken HTTP/1.1


Debugging the code, requestToken only has value and secret properties - no authenticate_url

So does   val svcAuth = :/("www.linkedin.com") / "uas" / "oauth" / "authenticate" represent an endpoint that gets called during authenticate_url? If so am I missing something in the logs, or does it now get logged?

If there isn't an API call, does "oauth" / "authenticate" represent how to parse the response from requestToken to obtain the authenticate_url? And does dispatch store it outside the requestToken so that the requestToken only has the info required for future calls to the API?

Thanks

logs

[console logger] dispatch: api.linkedin.com POST /uas/oauth/requestToken?scope=r_basicprofile%2Cr_emailaddress HTTP/1.1
[console logger] dispatch: api.linkedin.com POST /uas/oauth/accessToken HTTP/1.1
[console logger] dispatch: api.linkedin.com GET /v1/people/~:(id,first-name,last-name,email-address) HTTP/1.1

Denis Bardadym

unread,
Nov 8, 2012, 6:54:08 AM11/8/12
to lif...@googlegroups.com
Hello.

I post full REPL session there to be more clear about process:

//needed imports
scala> import dispatch._
scala> import dispatch.oauth._
scala> import dispatch.oauth.OAuth._

//first it is consumer token 
scala> val consumer = Consumer("YOU_APP_KEY", "YOU_APP_SECRET")
//step 1 getting from linked in request token - dispatch call
scala> val requestToken = Http(Auth.request_token(consumer, "http://localhost/callback", LinkedInAPI.defaultPermissions))
//step 2 obtaining authentication url
scala> Auth.authenticate_url(requestToken).to_uri.toString

//there i open browser and go to this url and accept request. Then linked in redirect me to http://localhost/callback (callbackUrl) with 2 uri params: oauth_token and oauth_verifier.

//about implementation there usually user will see popup window with this url or full site redirection to this url

scala> val oauth_verifier= "73848"
oauth_verifier: java.lang.String = 73848

scala> val accessToken = Http(Auth.access_token(consumer, requestToken, oauth_verifier))
scala> //now i can use this token for authorized calls
scala> new LinkedInAPI(consumer, accessToken).currentPerson
res1: ingo.services.linkedin.LinkedInAPI.Person = 
Person(Some(ApiStandardProfileRequest(Headers(1,List(HeaderValue(x-li-auth-token,name:TQUF))))),Some(Date(2,6,1989)),Some(Denis),Some(bardad...@gmail.com),Some(Bardadym),Some(S5wDjU75D5),Some(Computer Software),Some(design patterns, algorithms, new technology, c++, java, smalltalk, js, python, frameworks,...

Hope this will help.


-- 
Denis Bardadym
Отправлено при помощи Sparrow

четверг, 8 ноября 2012 г. в 15:21, bg написал:

bg

unread,
Nov 8, 2012, 7:04:20 AM11/8/12
to lif...@googlegroups.com

The simplified version of my question is 

Does scala> Auth.authenticate_url(requestToken).to_uri.toString result in my server making a call to a Linked in API?

If yes - why doesn't that show up in dispatch logging like the other calls?
If no - where does the uri I am redirecting to come from?

Its just to get my understanding of the process complete, I have got the code to work, so thank you very much for all your input.

Denis Bardadym

unread,
Nov 8, 2012, 7:09:08 AM11/8/12
to lif...@googlegroups.com
Does scala> Auth.authenticate_url(requestToken).to_uri.toString result in my server making a call to a Linked in API?
No, it do not make call (all calls are doing with http executors like Http object or dispatch.nio.http and so on). 

If no - where does the uri I am redirecting to come from?
This is required by OAuth spec. User should accept all permissions which you ask on host site.
-- 
Denis Bardadym
Отправлено при помощи Sparrow

четверг, 8 ноября 2012 г. в 16:04, bg написал:


The simplified version of my question is 



bg

unread,
Nov 8, 2012, 7:50:26 AM11/8/12
to lif...@googlegroups.com
OK, thanks for clarifying that for me, I'm pretty comfortable with the end to end process now.

bg

unread,
Nov 20, 2012, 7:08:00 AM11/20/12
to lif...@googlegroups.com
Hi guys, I'm having a little trouble with Google oAuth2.0 now, I created a separate post, https://groups.google.com/forum/?fromgroups=#!topic/liftweb/-RcIfKdTO4M

If anyone has any thoughts that would be much appreciated.

Brent


On Thursday, November 8, 2012 12:50:26 PM UTC, bg wrote:
OK, thanks for clarifying that for me, I'm pretty comfortable with the end to end process now.
Reply all
Reply to author
Forward
0 new messages