280 likes | 445 Views
Web Services with OAuth. What is OAuth?. A simple open standard for API Authentication. Do we need it? We’ve got OpenID. Not a replacement, a complementary API. OAuth is Authorization, Openid is Authentication
E N D
What is OAuth? • A simple open standard for API Authentication
Do we need it? We’ve got OpenID • Not a replacement, a complementary API. • OAuth is Authorization, Openid is Authentication • OpenID users don’t have passwords, so can’t ask them for that when they try to access the API • OAuth is token based, does not require password
A bit more about OAuth • Not a new idea - FlickrAuth, Google AuthSub, BBAuth, etc. • Open Standard - http://oauth.net/ • Wide industry support • AOL, Eye-Fi, Facebook, Garmin, Google, LinkedIn, Ma.gnolia, Microsoft, MySpace, Plaxo, Pownce, Salesforce, Songbird, Veodia, and Yahoo!. and more! • Easy to understand • Easy to implement
The Conversation • <me> Hey Appfresh update my iusethis count<appfresh> Lemme check with iusethis • <appfresh> Hey iusethis, can I update marcus’ apps?<iusethis> Here’s a ticket, give that to him,and I’ll check with him* iusethis hands appfresh a request token • <appfresh> Hey marcus, get this ticket stamped with iusethis so I can update your data for you, please<me> *meh*, allright • * appfresh opens a browser window to iusethis<iusethis> Marcus, you fine with appfresh updating your counts?<me> Go ahead already, I’m waiting here<iusethis> Ok, here’s a stamp for your ticket.* iusethis marks the token as approved • * appfresh hands the request token over to iusethis and gets an access token in return once iusethis sees that it is approved* appfresh updates my iusethis counts. *yay*
The data flow • Consumer must be registered with service • Consumer sends a signed OAuth request to the request_token endpoint, service provider returns a token as a post body in the response content • Consumer opens the user auth endpoint with the specified token. if web service, provide a callback to redirect back after auth. user verifies token, and returns to service • Consumer hits access token endpoint with request token and gets a valid access token
The OAuth request • POST/GET Request • oauth_consumer_key => 'foo', • oauth_consumer_secret => 'bar', • oauth_request_method => 'POST', • signature_method => 'HMAC-SHA1', • oauth_timestamp => '1191242090', • oauth_nonce => 'hsu94j3884jdopsl',
Adding this for your Catalyst based API • We need to store data somewhere • I’ll use a DBIC model in this example: • DB::Consumer • DB::RequestToken • DB::AccessToken • Then we just use Net::OAuth directly in the controller:
request_token method • my $oauth_params = $c->get_oauth_parameters(@params); • my $consumer=$c->model('DB::Consumer')->find( • $c->req->params->{consumer_secret}) • or $c->detach('/usererror', • ["Consumer not registered"]); • my $request = eval { • Net::OAuth::RequestTokenRequest->new( • request_url => $c->req->uri, • request_method => $c->req->method, • consumer_secret => $consumer->secret, • signature_key => $c->get_signature_key, • ) • }; # handle errors here • $c->stash->{requesttoken}= • $consumer->new_requesttoken($request);
verifying the request • sub verify_access : Local { • my ($self,$c)=@_; • $c->res->redirect($c->uri_for(‘/login’) • unless $c->user_exists; • my @params = qw/consumer_key signature_method • signature timestamp nonce token version/; • # find and validate token • return $c->res->redirect('/login') • unless $c->user_exists; • if($c->req->params->{verify}) { • $token->verified(1);$token update; • } • }
access_token • my ($self,$c)=@_; • my $consumer= ... # like previous • my $request = eval { Net::OAuth::AccessTokenRequest • ->new( • request_url => $c->uri_for( • '/oauth/access_token'), • request_method => $c->req->method, • consumer_secret => $consumer->secret, • token_secret => $request_token->secret, • signature_key => $signature_key, }; • $token= $consumer • ->get_access_token($oauth_params{token}) || • $c->detach('/usererror',['Request token not found']); • $c->stash->{access_token}=$token • ->create_access_token($token);
A bit of work • In addition you need a method to verify that the access token was provided for api methods • A bit of a hassle right now • Will commit a server example to catalyst-trunk shortly • Watch for Catalyst-Controller-OAuth sometime in the near future. • Might also be a Reaction component
Jifty • Jifty::Plugin::OAuth makes this easy. • Add this to your config file : • And presto: framework: Plugins: - OAuth: {}
Jifty continued • Make sure that /oauth/authorize requires login. • Make sure that /oauth/request_token and /oauth/access_token doesn’t. • In beta. Still has some limitations. Consumers has to be manually registered.
Behind the curtain • my $request = Net::OAuth ->request("request token")->new( $c->_default_request_params, request_url => $c->config->{request_token_endpoint}, extra_params => { scope=> $c->config->{request_scope}, }); • $request->sign($c->_get_key); • my $res = $ua->request(GET $request->to_url);
Behind the curtain • $request = Net::OAuth->request('user auth')->new( token => $response->token, callback => $c->uri_for('/callback'),); • return $c->res->redirect($request->to_url($c->config->{user_auth_endpoint}));
Behind the curtain • my $response = Net::OAuth->response('user auth') ->from_hash($c->req->params); • my $request = Net::OAuth->request("access token") ->new( $c->_default_request_params,request_url => $c->config->{access_token_endpoint},token => $response->token,token_secret => ''); • $request->sign($c->_get_key); • my $res = $ua->request(GET $request->to_url);
Behind the curtain • $response = Net::OAuth ->response('access token') ->from_post_body($res->content); • $c->session->{token}= $response->token; • # use the tokenmy $request = Net::OAuth->request("protected resource")->new($c->_default_request_params,request_url => $c->config->{contacts_feed_url},token => $c->session->{token},token_secret => '',); • # sign, lwpmy $res = $ua->request(GET($request->request_url, Authorization => $request->to_authorization_header));
Get the Source • Ported from the Original CGI::App example included in Net::OAuth • Get the source in Catalyst repo • http://dev.catalyst.perl.org/repos/Catalyst/trunk/examples/OAuthExample
Thank you! marcus@nordaaker.com