Android Question OAuth Question

Marco Nissen

Active Member
Licensed User
Longtime User
Hi

I'm already using OAuth heavily on iOS to interact with a huge server based API, see here: http://www.ravelry.com/api

Now, I'd like to implement also an Android based app, but am struggling with OAuth

I have these URLs that need to be used:
I tried lots of examples & tutorials (like twitter, google mail, facebook feed, etc) but none of them really worked. Basically, I need to call request_token initially, and have to open the first login window using a webview from the server to enter username + password.

I thought I could use the OAuth library, but was missing the OAuthProvider to set the URL's

So: is there anybody who is able to provide some hints what the best approach would be ?

Your help is really appreciated

Thank you,
Marco
 

Marco Nissen

Active Member
Licensed User
Longtime User
The OAuth library wraps this open source project: https://code.google.com/p/oauth-signpost/wiki/GettingStarted

It should be simple to add support for OAuthProvider. If you can tell me the methods that you need to call then I will help you expose these methods.

Excellent. Basically, it's everything that is on the getting started page: https://code.google.com/p/oauth-signpost/wiki/GettingStarted

Does that makes sense?

As far as I understand, you already implemented the SIGN piece to be able to sign http requests for regular queries to the web service.

However, I was missing the steps before.
If I had a OAuthProvider class, I could initialized it with the three URL's from above, and then using the "retrieveRequestToken" method retrieve a URL for the authorization step.

Once I successfully authenticated, I could use method "retrieveAccessToken" to get the token for the sign process for regular calls.

One thing that I don't know is how the callback from authorization will actually trigger calling the "JobDone" method in b4a, but maybe it's easy for you to determine?

Again, the protocol is OAuth1.0a

Thanks
Marco
 
Last edited:
Upvote 0

Erel

B4X founder
Staff member
Licensed User
Longtime User
You can use JavaObject library to create an OAuthProvider:
B4X:
Dim consumer As OAuth
consumer.Initialize(...)
Dim provider As JavaObject = CreateOAuthProvider(...)
Dim url As String = provider.RunMethod("retrieveRequestToken", Array(consumer, "callback_url"))

Sub CreateOAuthProvider(RequestUrl As String, AccessUrl As String, AuthorizeUrl As String) As JavaObject
   Dim provider As JavaObject
   provider.InitializeNewInstance("oauth.signpost.commonshttp.CommonsHttpOAuthProvider", Array(RequestUrl, _
     AccessUrl, AuthorizeUrl)
   Return provider
End Sub
 
Upvote 0

Marco Nissen

Active Member
Licensed User
Longtime User
Great, that works well.
Now I can imagine how to access all the other Java code, really cool.
The only thing is that such http connections have to be moved into background tasks, is there a best practice in b4a ?
 
Upvote 0

Marco Nissen

Active Member
Licensed User
Longtime User
You can use JavaObject library to create an OAuthProvider:
B4X:
Dim consumer As OAuth
consumer.Initialize(...)
Dim provider As JavaObject = CreateOAuthProvider(...)
Dim url As String = provider.RunMethod("retrieveRequestToken", Array(consumer, "callback_url"))

Sub CreateOAuthProvider(RequestUrl As String, AccessUrl As String, AuthorizeUrl As String) As JavaObject
   Dim provider As JavaObject
   provider.InitializeNewInstance("oauth.signpost.commonshttp.CommonsHttpOAuthProvider", Array(RequestUrl, _
     AccessUrl, AuthorizeUrl)
   Return provider
End Sub

Hi Erel

One other comment, and question (in addition to the previous background task question)

I have succeeded in the following
* authentication
* login to web form
* handling the callback
* retrieving the verifier
* request the access token+ secret

now I need to sign a post request, but the libraries available don't seem to match
OAuth seems to be based on Apache-HttpRequest, httputils2 uses a different one (I get an exception for that)

Can you please tell me how I should create a httputils2 post statement and sign it in the best way ?

thanks
Marco
 
Upvote 0

Erel

B4X founder
Staff member
Licensed User
Longtime User
The only thing is that such http connections have to be moved into background tasks, is there a best practice in b4a ?
Http requests are always sent in the background. You need to handle the relevant events to process the response.

Can you please tell me how I should create a httputils2 post statement and sign it in the best way ?
You can call Job.PostString and then get the request and sign it.

See this link: http://www.b4x.com/android/forum/threads/set-http-request-header-with-httputils2.39413/
 
Upvote 0

Marco Nissen

Active Member
Licensed User
Longtime User
These are now the results of my efforts, so if anybody else wants to copy & paste it, you're very welcome

Main:
B4X:
Sub Process_Globals
    Dim AuthorizationCode, AccessToken As String, AccessSecret
    Dim clientID="the key" As String
    Dim clientSecret="the secret" As String
End Sub

Sub Globals
   Dim provider As JavaObject
   Dim consumer As JavaObject
End Sub

Sub Button1_Click
    If AuthorizationCode = "" Then
        consumer   = CreateOAuthConsumer(clientID,clientSecret)
        provider   = CreateOAuthProvider("https://api.ravelry.com/oauth/request_token?scope=forum-write+message-write", _
            "https://api.ravelry.com/oauth/access_token","https://api.ravelry.com/oauth/authorize")
        provider.RunMethod("setOAuth10a",     Array(True))
        Dim url As String = provider.RunMethod("retrieveRequestToken", Array(consumer, "myapp://oauth"))
        Dim scope As String
        scope = "https://api.ravelry.com"
        Dim wv As WebView
        wv.Initialize("wv")
        Activity.AddView(wv, 0, 0, 100%x, 100%y)
        wv.LoadUrl(url )
        Button1.Enabled = False
    End If
End Sub

Sub CreateOAuthProvider(RequestUrl As String, AccessUrl As String, AuthorizeUrl As String) As JavaObject
   provider.InitializeNewInstance("oauth.signpost.commonshttp.CommonsHttpOAuthProvider", Array(RequestUrl, _
     AccessUrl, AuthorizeUrl))
   Return provider
End Sub

Sub CreateOAuthConsumer(key As String, secret As String) As JavaObject
   consumer.InitializeNewInstance("oauth.signpost.commonshttp.CommonsHttpOAuthConsumer", Array(clientID, _
   clientSecret))
   Return consumer
End Sub

Sub wv_PageFinished (url As String)
    If url.StartsWith("myapp") Then
        Dim i As Int
        Dim keystr As String= "oauth_verifier="
        Dim verifier As String
        i=url.indexof(keystr)+keystr.Length
        verifier = url.SubString(i)
        provider.RunMethod("retrieveAccessToken",         Array(consumer, verifier))
        AccessToken=consumer.RunMethod("getToken",Null)
        AccessSecret=consumer.RunMethod("getTokenSecret", Null)
        StartActivity(getUser)
    End If
End Sub

In Activity getUser:

B4X:
Sub Activity_Create(FirstTime As Boolean)
    Dim  job3 As HttpJob
    job3.Initialize("UserDetails", Me)
    job3.Download("https://api.ravelry.com/current_user.json")
    Dim myauth As OAuth
    myauth.Initialize(Main.clientID,Main.clientSecret)
    myauth.SetTokenWithSecret(Main.AccessToken,Main.AccessSecret)
     myauth.Sign(job3.GetRequest)
End Sub

Sub JobDone (Job As HttpJob)
  If Job.Success = True Then
      Select Job.JobName
          Case "UserDetails"
            Log(Job.GetString2("UTF8"))
      End Select
  Else
      Log("Error: " & Job.ErrorMessage)
      ToastMessageShow("Error: " & Job.ErrorMessage, True)
      Log(Job)
  End If
  Job.Release
End Sub

Results are absoletely OK, now I just need to continue digging deeper into JSON parsing

{"user": {"large_photo_url":"http://avatars.ravelry.com/wurzelkraut/229713018/2014-04-11-Marco_Nissen-1413-MySite_jpg_xlarge.jpg","photo_url":"http://avatars.ravelry.com/wurzelkraut/229713018/2014-04-11-Marco_Nissen-1413-MySite_jpg_large.jpg","small_photo_url":"http://avatars.ravelry.com/wurzelkraut/229713018/2014-04-11-Marco_Nissen-1413-MySite_jpg_small.jpg","id":2528927,"tiny_photo_url":"http://avatars.ravelry.com/wurzelkraut/229713018/2014-04-11-Marco_Nissen-1413-MySite_jpg_tiny.jpg","username":"wurzelkraut"}}

Another question:

1) Is there an automatic mechanism to convert the entirety of possible API Calls to classes?
There are tons of them, and it would be just much more convenient

2) what is the best way to parse JSON result objects, and create JSON objects to be used for POST requests?

Thanks
Marco
 
Last edited:
Upvote 0

Marco Nissen

Active Member
Licensed User
Longtime User
yes, super simple. just succeeded. What I recommend is to rewrite the OAuth library to avoid such complex workarounds with the JavaObject
Anyhow, for me it works now
 
Upvote 0

johnB

Active Member
Licensed User
Longtime User
This Looks nice and simple, can I ask a couple of question

I don't understand This line

Dim AuthorizationCode, AccessToken As String, AccessSecret - what is AccessSecret defined as???? String?????

And

in the Sub

Sub wv_PageFinished (url As String)

i get an error on the line

StartActivity(getUser) - getUser isn't defined, Am I missing a library

Thanks in anticipation
 
Upvote 0

DonManfred

Expert
Licensed User
Longtime User
getUser isn't defined, Am I missing a library
In Activity getUser:

B4X:
Sub Activity_Create(FirstTime As Boolean)
    Dim  job3 As HttpJob
    job3.Initialize("UserDetails", Me)
    job3.Download("https://api.ravelry.com/current_user.json")
    Dim myauth As OAuth
    myauth.Initialize(Main.clientID,Main.clientSecret)
    myauth.SetTokenWithSecret(Main.AccessToken,Main.AccessSecret)
     myauth.Sign(job3.GetRequest)
End Sub

Sub JobDone (Job As HttpJob)
  If Job.Success = True Then
      Select Job.JobName
          Case "UserDetails"
            Log(Job.GetString2("UTF8"))
      End Select
  Else
      Log("Error: " & Job.ErrorMessage)
      ToastMessageShow("Error: " & Job.ErrorMessage, True)
      Log(Job)
  End If
  Job.Release
End Sub
 
Upvote 0
Top