[aerogear-dev] OAuth2 Adapter

Corinne Krych corinnekrych at gmail.com
Fri Dec 20 02:40:40 EST 2013


Hello All,

I've implemented OAuth2 for iOS [1]. I still need some cleaning/refactoring before sending a PR.
Following Lucas demo, I've tested it to display a list of your Google Drive files. You can test it here [2]. I will also do a PR for our ios-cookbook to add GoogleDrive app.

Note that the implementation is not yet complete, we'll need to add:
-revoke
-refresh

Main difference with js implementation is that I don't store permanently the accessTokens, I prefer to let the application developer decide whether or not the application should save the accessToken. OAuth2 interface is here [3]

Managing OAuth callback into the application was the tricky point for Google+ as iOS implementation is poorly documented (I will add a section on Readme how to configure Google project etc…), Android version should be easier.

++
Corinne
[1] https://github.com/corinnekrych/aerogear-ios/tree/AGIOS-138/AeroGear-iOS/AeroGear-iOS/security/Authorizer
[2] https://github.com/corinnekrych/GoogleDrive
[3] https://github.com/corinnekrych/aerogear-ios/blob/AGIOS-138/AeroGear-iOS/AeroGear-iOS/security/Authorizer/AGAuthzModule.h

On Dec 19, 2013, at 1:49 PM, Luke Holmquist <lholmqui at redhat.com> wrote:

> https://github.com/aerogear/aerogear-js/pull/58
> 
> I reopened it
> 
> Sent from my iPhone
> 
>> On Dec 19, 2013, at 6:08 AM, Bruno Oliveira <bruno at abstractj.org> wrote:
>> 
>> Do we have a PR for it? Works like a charm on chrome, didn’t went well for safari. But let’s start simple, attach a PR please, I’m anxious to test it.
>> 
>> --  
>> abstractj
>> 
>>> On December 19, 2013 at 6:45:14 AM, Sebastien Blanc (scm.blanc at gmail.com) wrote:
>>> 
>>> I just tested the demo, very cool, work as advertised ;)
>>> 
>>> 
>>>> On Wed, Dec 18, 2013 at 8:45 PM, Lucas Holmquist wrote:  
>>>> 
>>>> i've created a new example here,
>>>> https://github.com/lholmquist/ag-google-drive
>>>> 
>>>> that hopefully shows the flow a bit
>>>> 
>>>>> On Aug 29, 2013, at 2:05 PM, Lucas Holmquist  
>>>> wrote:
>>>> 
>>>> i did get it to work
>>>>> On Aug 29, 2013, at 2:04 PM, Sebastien Blanc  
>>>> wrote:
>>>> 
>>>> This update is really cool, is the pipe test flow working ?
>>>> 
>>>> 
>>>>> On Thu, Aug 29, 2013 at 7:57 PM, Lucas Holmquist wrote:  
>>>>> 
>>>>> i've updated the sample again https://github.com/lholmquist/oauth2test  
>>>>> 
>>>>> this time i added a pipe object and used pipe.read to see how 
>>> the flow
>>>>> would be
>>>>> 
>>>>> 
>>>>> On Aug 29, 2013, at 11:55 AM, Lucas Holmquist  
>>>>> wrote:
>>>>> 
>>>>> i've updated the sample app with the new flow
>>>>> 
>>>>> https://github.com/lholmquist/oauth2test
>>>>> 
>>>>> 
>>>>> On Aug 29, 2013, at 9:23 AM, Lucas Holmquist  
>>> wrote:
>>>>> 
>>>>> ok, Kris had some thoughts on a better flow, so i refactored  
>>> the code a
>>>>> bit and i think i like this way a bit better.
>>>>> 
>>>>> New Flow - Client Flow - Standalone for now, possible integration  
>>> with
>>>>> pipes First Time - No Access Token stored( in localStorage  
>>> )
>>>>> 
>>>>> User will create the Authorization Object stuff with settings/options  
>>>>> 
>>>>> var thing = AeroGear.Authorization();
>>>>> 
>>>>> thing.add({
>>>>> name: "coolThing",
>>>>> settings: {
>>>>> clientId: "12345.apps.googleusercontent.com",
>>>>> redirectURL: "http://localhost:8000/redirector.html",  
>>>>> tokenValidationEndpoint: "https://www.googleapis.com/oauth2/v1/tokeninfo",  
>>>>> authEndpoint: "https://accounts.google.com/o/oauth2/auth",  
>>>>> revokeURL: "https://accounts.google.com/o/oauth2/revoke",  
>>>>> scopes: "https://www.googleapis.com/auth/userinfo.profile",  
>>>>> prompt: "force"
>>>>> }
>>>>> });
>>>>> 
>>>>> *should have the ability to specify more settings, based on  
>>> the spec*
>>>>> 
>>>>> The user would then call some method( currently not good names  
>>> are coming
>>>>> to me, maybe validate ) that takes success and error callbacks.  
>>>>> 
>>>>> thing.services.coolThing.validate({
>>>>> success: function( response ){
>>>>> console.log( "Should be response from Validating the access  
>>> token", response );
>>>>> },
>>>>> error: function( error ) {
>>>>> //should contain a constructed URL for the user
>>>>> console.log( "error", error );
>>>>> }
>>>>> });
>>>>> 
>>>>> Since this is the first time, the error callback will be called  
>>> and will
>>>>> contain the constructed URL that the user should do the popup  
>>> redirect
>>>>> dance with to get an access token.
>>>>> 
>>>>> *what "dance" they do is up to the developer*
>>>>> 
>>>>> Once that happens and they have the access token, they would  
>>> call the
>>>>> validate method again.
>>>>> 
>>>>> this makes sure that the token they recieved is validated and  
>>> will also
>>>>> return some other meta data related to the token, like refresh  
>>> time.
>>>>> 
>>>>> Once the token has been validated, it will be stored in localStorage  
>>> and
>>>>> would be accessable with the key of ag-oauth2-whatever_the_client_ID_is  
>>> .
>>>>> 
>>>>> so in this example it would be something like:
>>>>> 
>>>>> ag-oauth2-12345.apps.googleusercontent.com
>>>>> 
>>>>> There is one problem i can see here though. If the user has to  
>>>>> applications with the same client ID but different scopes  
>>> assigned, this
>>>>> would be a problem. That use case could be considered bad practice  
>>> anyway
>>>>> 
>>>>> The user can then call the "callService"( yes, again, crappy  
>>> name )
>>>>> method to get access to the service they want.
>>>>> 
>>>>> thing.services.coolThing.callService({
>>>>> serviceURL: "https://www.googleapis.com/oauth2/v2/userinfo",  
>>>>> success: function( response ){
>>>>> console.log( "Should be the response from the call", response  
>>> );
>>>>> },
>>>>> error: function( error ) {
>>>>> console.log( "error", error );
>>>>> }
>>>>> });
>>>>> 
>>>>> All these methods would have success/error callbacks.
>>>>> Token Expiration
>>>>> 
>>>>> If the user makes a call to a service, using the callService  
>>> method, and
>>>>> they recieve an error such as not authorized or token invalid  
>>> or token
>>>>> expired, I'm thinking we send what the "contructed URL" should  
>>> be, similar
>>>>> to the validate method described above.
>>>>> 
>>>>> Since this is a Client Side flow, there is no refresh token,  
>>> so the
>>>>> client wouldn't be able to refresh the access token without  
>>> doing the
>>>>> "dance" again.
>>>>> 
>>>>> 
>>>>> 
>>>>> On Aug 27, 2013, at 1:57 PM, Lucas Holmquist  
>>> wrote:
>>>>> 
>>>>> i've hacked together a sample app that shows sort of the flow.  
>>>>> 
>>>>> https://github.com/lholmquist/oauth2test
>>>>> 
>>>>> it is still very rough
>>>>> 
>>>>> On Aug 27, 2013, at 12:42 PM, Bruno Oliveira  
>>> wrote:
>>>>> 
>>>>> +1 keep it simple, please
>>>>> 
>>>>> Lucas Holmquist wrote:
>>>>> 
>>>>> 
>>>>> On Aug 27, 2013, at 3:39 AM, Sebastien Blanc > >> >>  
>>> wrote:
>>>>> 
>>>>> Hi,
>>>>> That sounds good !
>>>>> Just one question, instead of using the callApi function couldn't  
>>> we
>>>>> pass the oauth module (called 'thing' in your example) to the  
>>> pipe
>>>>> directly, using the 'authenticator' setting. Behind the  
>>> scene, the
>>>>> pipe manager will append the oauth token to the query or add  
>>> the
>>>>> bearer header ?
>>>>> 
>>>>> 
>>>>> I'm not sure if that is what this is going to do. This is more of  
>>> an
>>>>> Authorization thing and i don't think it totally fits the pipeline  
>>>>> stuff. ( or it would make it a bit more complicated, and we want  
>>> to keep
>>>>> it simple )
>>>>> 
>>>>> 
>>>>> i should probably change the method to be "authorize" instead  
>>>>> 
>>>>> Seb
>>>>> 
>>>>> 
>>>>> 
>>>>> On Mon, Aug 26, 2013 at 8:05 PM, Lucas Holmquist > >> >>  
>>> wrote:
>>>>> 
>>>>> 
>>>>> OAuth2 AeroGear Workflow - High Level
>>>>> 
>>>>> 
>>>>> Using Google api's
>>>>> 
>>>>> /Server Side/
>>>>> 
>>>>> 1. user needs to first create an "application/project" to  
>>> get an
>>>>> api key
>>>>> 2. Then they would choose the services/api's then would like  
>>>>> there application to access
>>>>> 3. other google server related items....
>>>>> 
>>>>> /Client Side/
>>>>> 
>>>>> 1. Create a new OAuth2 module thing
>>>>> 2. Get access token for the services would need to specify the  
>>>>> services they would like to access
>>>>> 3. validate the token
>>>>> 4. make calls to the service
>>>>> 
>>>>> 
>>>>> API
>>>>> 
>>>>> |var thing = AerGear.OAuth2({
>>>>> name: googleEndPoints, //Just a Name
>>>>> clientID: "12345" //The client ID of the app from the
>>>>> API console
>>>>> settings: {
>>>>> permissions: "..",
>>>>> ...
>>>>> }
>>>>> }).somecoolmodulename.googleEndPoints;
>>>>> |
>>>>> 
>>>>> /Settings: Multiple settings based on paramters here
>>>>> /  
>>>>> 
>>>>> /Methods/
>>>>> 
>>>>> 
>>>>> authenticate
>>>>> 
>>>>> this will authenticate with the server to get the access token  
>>> and
>>>>> then validate the token, once that is all good then the response  
>>>>> is returned.
>>>>> 
>>>>> |thing.authenticate({
>>>>> success:{},
>>>>> error:{},
>>>>> settings: {
>>>>> //probably some settings here, like URL overides and such  
>>>>> }
>>>>> });
>>>>> |
>>>>> 
>>>>> 
>>>>> callApi
>>>>> 
>>>>> not really a good name, but it would basically call the remote  
>>>>> api/services. we could either do a query string option or a  
>>> Head
>>>>> option
>>>>> 
>>>>> example:
>>>>> 
>>>>> |curl '
>>>>> https://www.googleapis.com/oauth2/v1/userinfo?access_token=1/fFBGRNJru1FQd44AzqT3Zg'  
>>>>> |
>>>>> 
>>>>> or
>>>>> 
>>>>> |curl -H "Authorization: Bearer {accessToken}"
>>>>> https://www.googleapis.com/oauth2/v1/userinfo
>>>>> |
>>>>> 
>>>>> code:
>>>>> 
>>>>> |thing.callApi({
>>>>> service: "userinfo", //don't really like this name either  
>>>>> success:{},
>>>>> error:{},
>>>>> settings: {
>>>>> ... //overridable baseURLs?
>>>>> }
>>>>> });
>>>>> |
>>>>> 
>>>>> 
>>>>> revoke
>>>>> 
>>>>> again, maybe not the best name. calls the "revoke" service,  
>>> to
>>>>> remove access to permissions
>>>>> 
>>>>> |thing.revoke({
>>>>> success: {},
>>>>> error: {},
>>>>> settings: {}
>>>>> });
>>>>> |
>>>>> 
>>>>> Behind the scenes on all these calls, the "access_token" is  
>>>>> beining used and possibly refreshed for the user, so they don't  
>>>>> have to worry about it. They just need to call authenticate  
>>> first.
>>>>> Maybe we can have a refresh method if the user wants to refresh  
>>>>> the tokens themselves. this would do the token "dance"
>>>>> 
>>>>> 
>>>>> 
>>>>> On Aug 26, 2013, at 1:35 PM, Bruno Oliveira > >> >>  
>>> wrote:
>>>>> 
>>>>> +1 I think is a good start to us.
>>>>> 
>>>>> Kris Borchers wrote:
>>>>> 
>>>>> I would like to see that but what you are saying makes sense.  
>>> It
>>>>> sounds like where I was headed with the Basic and Digest
>>>>> adapters before I ran into browser security issues with headers.  
>>>>> I think and authorization API that basically just wraps itself  
>>>>> around secured endpoints works for me.
>>>>> 
>>>>> 
>>>>> --
>>>>> abstractj
>>>>> 
>>>>> 
>>>>> _______________________________________________
>>>>> aerogear-dev mailing list
>>>>> aerogear-dev at lists.jboss.org  
>>>>> https://lists.jboss.org/mailman/listinfo/aerogear-dev  
>>>>> 
>>>>> 
>>>>> 
>>>>> _______________________________________________
>>>>> aerogear-dev mailing list
>>>>> aerogear-dev at lists.jboss.org  
>>>>> https://lists.jboss.org/mailman/listinfo/aerogear-dev  
>>>>> 
>>>>> 
>>>>> _______________________________________________
>>>>> aerogear-dev mailing list
>>>>> aerogear-dev at lists.jboss.org  
>>>>> https://lists.jboss.org/mailman/listinfo/aerogear-dev  
>>>>> 
>>>>> 
>>>>> _______________________________________________
>>>>> aerogear-dev mailing list
>>>>> aerogear-dev at lists.jboss.org
>>>>> https://lists.jboss.org/mailman/listinfo/aerogear-dev  
>>>>> 
>>>>> 
>>>>> --
>>>>> abstractj
>>>>> 
>>>>> 
>>>>> _______________________________________________
>>>>> aerogear-dev mailing list
>>>>> aerogear-dev at lists.jboss.org
>>>>> https://lists.jboss.org/mailman/listinfo/aerogear-dev  
>>>>> 
>>>>> 
>>>>> _______________________________________________
>>>>> aerogear-dev mailing list
>>>>> aerogear-dev at lists.jboss.org
>>>>> https://lists.jboss.org/mailman/listinfo/aerogear-dev  
>>>>> 
>>>>> 
>>>>> _______________________________________________
>>>>> aerogear-dev mailing list
>>>>> aerogear-dev at lists.jboss.org
>>>>> https://lists.jboss.org/mailman/listinfo/aerogear-dev  
>>>>> 
>>>>> 
>>>>> _______________________________________________
>>>>> aerogear-dev mailing list
>>>>> aerogear-dev at lists.jboss.org
>>>>> https://lists.jboss.org/mailman/listinfo/aerogear-dev  
>>>>> 
>>>>> 
>>>>> 
>>>>> _______________________________________________
>>>>> aerogear-dev mailing list
>>>>> aerogear-dev at lists.jboss.org
>>>>> https://lists.jboss.org/mailman/listinfo/aerogear-dev  
>>>> 
>>>> _______________________________________________
>>>> aerogear-dev mailing list
>>>> aerogear-dev at lists.jboss.org
>>>> https://lists.jboss.org/mailman/listinfo/aerogear-dev  
>>>> 
>>>> 
>>>> _______________________________________________
>>>> aerogear-dev mailing list
>>>> aerogear-dev at lists.jboss.org
>>>> https://lists.jboss.org/mailman/listinfo/aerogear-dev  
>>>> 
>>>> 
>>>> 
>>>> _______________________________________________
>>>> aerogear-dev mailing list
>>>> aerogear-dev at lists.jboss.org
>>>> https://lists.jboss.org/mailman/listinfo/aerogear-dev  
>>> _______________________________________________
>>> aerogear-dev mailing list
>>> aerogear-dev at lists.jboss.org
>>> https://lists.jboss.org/mailman/listinfo/aerogear-dev  
>> 
>> 
>> _______________________________________________
>> aerogear-dev mailing list
>> aerogear-dev at lists.jboss.org
>> https://lists.jboss.org/mailman/listinfo/aerogear-dev
> 
> _______________________________________________
> aerogear-dev mailing list
> aerogear-dev at lists.jboss.org
> https://lists.jboss.org/mailman/listinfo/aerogear-dev




More information about the aerogear-dev mailing list