{"id":293,"date":"2010-06-07T04:16:26","date_gmt":"2010-06-07T11:16:26","guid":{"rendered":"http:\/\/blog.monnet-usa.com\/?p=293"},"modified":"2010-06-07T04:16:26","modified_gmt":"2010-06-07T11:16:26","slug":"transform-your-ruby-camping-web-app-into-an-oauth-provider","status":"publish","type":"post","link":"https:\/\/blog.monnet-usa.com\/?p=293","title":{"rendered":"Transform Your Ruby Camping Web App Into An OAuth Provider"},"content":{"rendered":"<style>\n\t\t\t\t\t\th3 {\ttext-decoration: underline; }<\/p>\n<p>\t\t\t\t\t\th5 \n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tmargin:0 50px 0 50px;\n\t\t\t\t\t\t}<\/p>\n<p>\t\t\t\t\t\t.download_panel\n\t\t\t\t\t\t{\n\t\t\t\t\t\tbackground-color: #EDD6AD; \n\t\t\t\t\t\tcolor: #555555; \n\t\t\t\t\t\tfont-weight:bold;\n\t\t\t\t\t\ttext-align:center;\n\t\t\t\t\t\tmargin:0 50px 0 50px;\n\t\t\t\t\t\tpadding:6px;\n\t\t\t\t\t\t}<\/p>\n<p>\t\t\t\t\t\t.details_table \n\t\t\t\t\t\t{border: 1px solid #f0f0f0;\n\t\t\t\t\t\tborder-spacing: 1px;\n\t\t\t\t\t\tbackground-color:white;\n\t\t\t\t\t\tmargin-left: 40px;\n\t\t\t\t\t\t}<\/p>\n<p>\t\t\t\t\t\t.details_table tr\n\t\t\t\t\t\t{\n\t\t\t\t\t\tvertical-align: top;\n\t\t\t\t\t\tborder-bottom: 1px solid LightGoldenRodYellow;\n\t\t\t\t\t\t}<\/p>\n<p>\t\t\t\t\t\t.details_table th\n\t\t\t\t\t\t{\n\t\t\t\t\t\tbackground-color:lightgray;\n\t\t\t\t\t\t}<\/p>\n<p>\t\t\t\t\t\t.details_table td\n\t\t\t\t\t\t{\n\t\t\t\t\t\tborder-bottom: 1px solid LightGoldenRodYellow;\n\t\t\t\t\t\t}<\/p>\n<\/style>\n<h3>Intro <\/h3>\n<p>Over the last year <a href='#oawp'>OAuth<\/a> or <b>Open Authorization<\/b> has really been gaining ground as a mechanism to open up\/free your data hosted on various web sites and let you share that data across sites. The surge in interest can be attributed to a couple developments:\n\t\t\t\t\t<\/p>\n<ol>\n<li>Wider availability of OAuth libraries on a wide array of platforms<\/li>\n<li>Twitter declaring its intention to switch from Basic Authentication to OAuth<\/li>\n<li>Google announcing OAuth for GMail<\/li>\n<li>Other high-profile such as NetFlix providing OAuth support<\/li>\n<\/ol>\n<p>Although a new <a href='oaspec2'>2.0<\/a> version of the OAuth specification is in development,<br \/>\n\t\t\t\t\tI wanted to have my Ruby <a href='#rc'>Camping<\/a>-based web applications act as <a href='#oa'>OAuth providers<\/a> now with <a href='oaspec1a'>1.0a<\/a>.<br \/>To make that happen I needed some kind of <a href='#tacaoa'>Camping OAuth plugin<\/a>. Since none existed it was time to build one!<\/p>\n<div  class='download_panel'>Click <a href='#oacasrc'>here<\/a> if you want to skip straight to the <a href='#oacasrc'>source code<\/a><\/div>\n<h3>Synopsis of an OAuth Flow<\/h3>\n<p>Before we can dive in the making of the <a href='#tacaoa'>Camping OAuth plugin<\/a> here is a quick overview of the basics of the OAuth functionality.<\/p>\n<p>First, an OAuth provider has the responsibility to manage <a href='#oaca'>client applications<\/a> (<b>OAuth consumers<\/b>) and associated <b>tokens<\/b> for a given <b>user<\/b>. The overall model looks like this:<br \/>\n\t\t\t\t\t<img src='.\/wp-content\/media\/camping-oauth-provider\/camping-oauth-model.png' width='540px'\/>\n\t\t\t\t\t<\/p>\n<p><a name='oamo'><\/a><\/p>\n<table class='details_table'>\n<tr>\n<th>Model<\/th>\n<th>Responsibilities<\/th>\n<\/tr>\n<tr>\n<td><a name='oaus'><\/a>User<\/td>\n<td>The user account on the service provider app<\/td>\n<\/tr>\n<tr>\n<td><a name='oaca'><\/a>ClientApplication<\/td>\n<td>The registration of a specific consumer app needing data from the service provider app<\/td>\n<\/tr>\n<tr>\n<td><a name='oatn'><\/a>OauthToken<\/td>\n<td>Authorization tokens are exchanged between the consumer and the provider.<br \/>\n\tThere are 2 types of tokens:<\/p>\n<table  class='details_table'>\n<tr><a name='oart'><\/a><\/p>\n<td><b>Request<\/b>Token<\/td>\n<td>The Request Token is a temporary credential token used to authenticate the <a href='#oaca'>Client Application<\/a> (consumer app) at the provider site. This token typically includes the key and secret issued by the provider for the consumer.<\/p>\n<p>\t\t\tOnce a Request Token has been authorized, an <a name='oave'>OAuth Verifier<\/a> is issued. The verifier is a verification code which will be passed back to the client application for use in subsequent requests.<\/td>\n<\/tr>\n<tr><a name='oaat'><\/a><\/p>\n<td><b>Access<\/b>Token<\/td>\n<td>The Access Token is the authorized token the <a href='#oaca'>Client Application<\/a> (consumer app) needs to pass to the provider every time it wants to invokes a given API on the provider site. The Access Token is issued once the <a href='#oart'>Request Token<\/a> has been explicitly authorized by the user logged in at the provider site.<\/td>\n<\/tr>\n<\/table>\n<\/td>\n<\/tr>\n<tr>\n<td><a name='oane'><\/a>OauthNonce<\/td>\n<td>A combination of a number used only once and a timestamp. The <a href='http:\/\/en.wikipedia.org\/wiki\/Cryptographic_nonce'>nonce<\/a> is used to prevent replay attacks during during an <a href='#oawp'>OAuth<\/a> exchange.<\/td>\n<\/tr>\n<\/table>\n<h3>OAuth Provider API<\/h3>\n<p>In addition to having the data infrastructure in place to manage <a href='#oaca'>client application<\/a> and <a href='#oatn'>tokens<\/a> for users, a provider also needs to expose a <b>specific OAuth API<\/b> in the form of <b>URL routes<\/b>:<\/p>\n<p>\t\t\t\t\t<img src='.\/wp-content\/media\/camping-oauth-provider\/camping-oauth-routes.png' style='margin-left: 50px;'\/><\/p>\n<p><a name='routes'><\/a><\/p>\n<table class='details_table'>\n<tr>\n<th>Route<\/th>\n<th>Usage<\/th>\n<\/tr>\n<tr>\n<td>oauth\/register<\/td>\n<td>Allows a user to register an OAuth <b>consumer<\/b> to access data (on its behalf) from an OAuth <b>provider<\/b><\/td>\n<\/tr>\n<tr>\n<td>oauth\/request_token<\/td>\n<td>Allows the consumer app to provide the <b>key<\/b> and <b>secret<\/b> associated with the user&#8217;s registration so that an OAuth <a href='#oart'>RequestToken<\/a> can be provided.<\/td>\n<\/tr>\n<tr>\n<td>oauth\/authorize<\/td>\n<td>Allows the user to explicitly <b>grant access<\/b> to the <b>consumer<\/b> app on the <b>provider<\/b> site<\/td>\n<\/tr>\n<tr>\n<td>callback<\/td>\n<td>Allows the OAuth provider to <b>pass<\/b> data (OAuth <a href='#oave'>verifier<\/a>) back to the consumer app<\/td>\n<\/tr>\n<tr>\n<td>oauth\/revoke<\/td>\n<td>Allows the user to explicitly <b>revoke access<\/b> to the <b>consumer app<\/b> on the provider site<\/td>\n<\/tr>\n<tr>\n<td>oauth\/access_token<\/td>\n<td>Allows the consumer app to obtain an OAuth <a href='#oaat'>AccessToken<\/a>, based on an OAuth <a href='#oart'>RequestToken<\/a> and an OAuth <a href='#oave'>verifier<\/a>. The OAuth <a href='#oaat'>AccessToken<\/a> can then be passed to the provider when invoking provider APIs.<\/td>\n<\/tr>\n<\/table>\n<p>And now here is the scenario illustrating models and routes together:\n\t\t\t\t\t<\/p>\n<ol>\n<li>User U registers consumer application C with provider application P<\/li>\n<li>User U logs in to consumer C<\/li>\n<li>User U invokes functionality in C requiring data (e.g. list of contacts) from provider P<\/li>\n<li>Consumer C asks provider P for an OAuth <a href='#oart'>Request Token<\/a> based on its key and secret<\/li>\n<li>Provider P validates that the user&#8217;s <a href='#oaca'>client application<\/a> is valid (based on its key and secret)<\/li>\n<li>Provider P returns an OAuth <a href='#oart'>Request Token<\/a> R containing an authorization url<\/li>\n<li>Consumer C redirects user U to the authorization url at Provider P<\/li>\n<li>User U authorizes the <a href='#oart'>request token<\/a> R<\/li>\n<li>Provider P redirects user U to Consumer C and provides an OAuth <a href='#oave'>verifier<\/a> V<\/li>\n<li>Consumer C asks provider P for an OAuth <a href='#oaat'>Access Token<\/a> based on the OAuth <a href='#oart'>request token<\/a> ID and the OAuth <a href='#oave'>verifier<\/a> V<\/li>\n<li>Provider P verifies the validitity of the <a href='#oave'>verifier<\/a> V for the token R<\/li>\n<li>Provider P returns an OAuth <a href='#oaat'>Access Token<\/a> A to consumer C<\/li>\n<li>Consumer C invokes an API on provider P using the OAuth <a href='#oaat'>Access Token<\/a> A<\/li>\n<li>Provider P verifies the validity of the OAuth <a href='#oaat'>access token<\/a> A<\/li>\n<li>Provider P executes the invoked API and returns the data to Consumer C<\/li>\n<li>Consumer C leverages the data for the desired functionality<\/li>\n<\/ol>\n<h3>OAuth in Ruby<\/h3>\n<p><a href='#pb'>Pelle Braendgaard<\/a> created an awesome implementation of <a href='#oarb'>OAuth for Ruby<\/a>. You can find the library on GitHub <a href='http:\/\/github.com\/mojodna\/oauth'>here<\/a>, and you can install it as a gem:<\/p>\n<pre class=\"brush: ruby\">\r\ngem install oauth\r\n<\/pre>\n<p>The gem contains:<\/p>\n<ol>\n<li>The types of OAuth consumer tokens: <a href='#oart'>RequestToken<\/a>, <a href='#oaat'>AccessToken<\/a><\/li>\n<li>The signing components<\/li>\n<li>The communication components to request\/exchange\/process tokens<\/li>\n<\/ol>\n<p>Ruby-OAuth is primarily used for an OAuth consumer application or site to request access to data hosted by an OAuth provider.<br \/>\n\t\t\t\t\tSo how do we actually build a provider?<br \/>\n\t\t\t\t\tWell there is another gem called the <a href=''>oauth-plugin<\/a>, which was primarily designed to easily add OAuth provider capabilities to a Rails web application. Let&#8217;s install it too.<\/p>\n<pre class=\"brush: ruby\">\r\ngem install oauth-plugin\r\n<\/pre>\n<h5>A.Rails<\/h5>\n<p>So assuming you have a Rails web app, you can use the <a href=''>oauth-plugin<\/a> to generate:<\/p>\n<ol>\n<li>The database migration script to create the new tables (ClientApplication, <a href='#oart'>RequestToken<\/a>, <a href='#oaat'>AccessToken<\/a>, Nonce) as well as to extend the existing user table<\/li>\n<li>The models you need to track <a href='#oaat'>access tokens<\/a> for a given user at a given <a href='#oaca'>client application<\/a><\/li>\n<li>The controller needed to manage access to a given user&#8217;s data by a <a href='#oaca'>client application<\/a><\/li>\n<li>The views, forms and partials needed to register\/manage access<\/li>\n<\/ol>\n<h5>B._why&#8217;s Camping<\/h5>\n<p>Although you can use the <a href='#oarb'>Ruby-OAuth<\/a> gem to act as an OAuth consumer, there was no provider plugin like for Rails. So I stated thinking: &#8220;What would _why do?&#8221;. If the OAuth Plugin&#8217;s approach is based on generation to fit the Rails approach (with script\/generate), then the <a href='#rc'>Camping<\/a> approach would have to be based on meta-programming. Let&#8217;s dive in the approach (or <a href='#addoaprsu'>skip<\/a> to the next section on how to add OAuth provider support).<\/p>\n<h3>Implementing An OAuth Plugin In Camping Using Metaprogramming<\/h3>\n<p>I decided to try to leverage as much as possible the templates and utility code from the oauth-plugin, but without duplicating the code. Pelle was also gracious to allow me to do so.<\/p>\n<p>In the &#8220;<a href='#rc'>Camping<\/a> way of [dev] life&#8221;, adding features through metaprogramming means:<\/p>\n<ol>\n<li>including common OAuthCampingPlugin behaviors in the application&#8217;s main module:\n<ul>\n<li>Common helper methods related to user management, logging, etc.<\/li>\n<li>Common controller filters<\/li>\n<\/ul>\n<p>\n\t\t\t\t\t\t<\/li>\n<li>extending modules with new class utility behaviors &#8211; such as logging\n<\/li>\n<li>including the common <a href='#oamo'>OAuth models<\/a> in the application&#8217;s Models module with new desired instance features in other classes or in other modules &#8211; such as:\n<ul>\n<li><a href='#oaca'>ClientApplication<\/a><\/li>\n<li><a href='#oatn'>OauthToken<\/a><\/li>\n<li><a href='#oane'>OauthNonce<\/a><\/li>\n<li><a href='#oart'>RequestToken<\/a><\/li>\n<li><a href='#oaat'>AccessToken<\/a><\/li>\n<\/ul>\n<p>\t\t\t\t\t\t\tThese classes are &#8220;mixed in&#8221; by reading the oauth-plugin model templates and applying them using module_eval.<\/p>\n<\/li>\n<li>extending the application&#8217;s Controllers module with new meta definitions for the standard <a href='#routes'>OAuth routes<\/a>:\n<ul>\n<li>\/oauth\/register<\/li>\n<li>\/oauth\/request_token<\/li>\n<li>\/oauth\/authorize<\/li>\n<li>\/oauth\/revoke<\/li>\n<li>\/oauth\/access_token<\/li>\n<\/ul>\n<p>\n\t\t\t\t\t\t<\/li>\n<li>including the OAuthCampingPlugin::OAuth and OAuthCampingPlugin::Helpers modules in each of the Camping controllers using class_eval.\n<\/li>\n<li>extending the application&#8217;s Controllers module with new meta definitions for common views\/partials:\n<ul>\n<li>Application registration<\/li>\n<li>Token authorization<\/li>\n<li>Token revocation<\/li>\n<li>Errors<\/li>\n<\/ul>\n<p>\n\t\t\t\t\t\t<\/li>\n<li>including the OAuthCampingPlugin view methods in the application&#8217;s Views module using module_eval. <\/li>\n<\/ol>\n<p><i>Note: if you are interested in Ruby <b>metaprogramming<\/b>, check-out the <a href='#'>reference<\/a> section.<\/i><\/p>\n<p>Here is a diagram illustrating the parallel between modules in your provider web app and the modules in the <a href='#tacaoa'>camping-oauth plugin<\/a>:<\/p>\n<p>\t\t\t\t\t<img src='.\/wp-content\/media\/camping-oauth-provider\/camping-oauth-layers.png' style='margin-left: 50px;'\/>\n\t\t\t\t\t<\/p>\n<p>\t\t\t\t\t<a name=\"addoaprsu\" ><\/a><\/p>\n<h3>Adding OAuth Provider Support To Your App<\/h3>\n<p>Here is the approach we will be taking:<\/p>\n<p><a name='caoatodo'><\/a><\/p>\n<table class='details_table'>\n<tr>\n<th>#<\/th>\n<th>To Do<\/th>\n<\/tr>\n<tr>\n<td><a href='#caoatodoa'>A<\/a><\/td>\n<td>Start with a basic Camping shell<\/td>\n<\/tr>\n<tr>\n<td><a href='#caoatodob'>B<\/a><\/td>\n<td>Customize the main module<\/td>\n<\/tr>\n<tr>\n<td><a href='#caoatodoc'>C<\/a><\/td>\n<td>Plug in the OAuth models<\/td>\n<\/tr>\n<tr>\n<td><a href='#caoatodod'>D<\/a><\/td>\n<td>Create a common helpers module<\/td>\n<\/tr>\n<tr>\n<td><a href='#caoatodoe'>E<\/a><\/td>\n<td>Plug in the OAuth controllers<\/td>\n<\/tr>\n<tr>\n<td><a href='#caoatodof'>F<\/a><\/td>\n<td>Plug in the OAuth common views<\/td>\n<\/tr>\n<tr>\n<td><a href='#caoatodog'>G<\/a><\/td>\n<td>Add basic login and registration capabilities<\/td>\n<\/tr>\n<tr>\n<td><a href='#caoatodoh'>H<\/a><\/td>\n<td>Protect our API(s) using OAuth filters<\/td>\n<\/tr>\n<\/table>\n<p>\t<\/p>\n<p>\t\t\t\t\t<a name='caoatodoa'><\/a><\/p>\n<h5>A. Let&#8217;s start with a basic Camping shell<\/h5>\n<p>Create an camping-oauth-provider.rb file and let&#8217;s create a basic traditional <a href='#rc'>Camping<\/a> shell for an application named CampingOAuthProvider:<\/p>\n<pre class=\"brush: ruby\">\r\ngem 'camping' , '>= 2.0'\t\r\n%w(rubygems active_record camping camping\/session markaby json erb).each { |lib| require lib }\r\n\r\nCamping.goes :CampingOAuthProvider\r\n\r\nmodule CampingOAuthProvider\r\n\tinclude Camping::Session\r\n\r\n\tdef CampingOAuthProvider.create\r\n\tend\r\nend\r\n\r\nmodule CampingOAuthProvider::Models\r\nend\r\n\r\nmodule CampingOAuthProvider::Helpers\r\nend\r\n\r\nmodule CampingOAuthProvider::Controllers\r\n\tclass Index\r\n\t\tdef get \r\n\t\t\trender :index\r\n\t\tend\r\n\tend\r\nend\r\n\r\nmodule CampingOAuthProvider::Views\r\n\tdef index\r\n\t\th1 'My CampingOAuthProvider App'\r\n\t\tdiv 'To be continued ...'\r\n\tend\r\nend\r\n\r\nCampingOAuthProvider.create\r\n<\/pre>\n<p>Now we have a skeletal <a href='#rc'>Camping<\/a> app that we can run as follows:<\/p>\n<pre class=\"brush: ruby\">\r\ncamping camping-oauth-provider.rb\r\n<\/pre>\n<p>Access the app from the browser at the following url:<\/p>\n<pre class=\"brush: ruby\">\r\nhttp:\/\/localhost:3001\/\r\n<\/pre>\n<p>For our controllers we will leverage Magnus Holm&#8217;s (a.k.a. @judofyr) excellent <a href='http:\/\/github.com\/judofyr\/filtering_camping'>filtering_camping<\/a> gem, which provides a <b>controller filter mechanism<\/b> similar to Rails filters, but in more basic and simpler way. So let&#8217;s install it:<\/p>\n<pre class=\"brush: ruby\">\r\ngem install filtering_camping\r\n<\/pre>\n<p>We will need to reference the four gems: filtering_camping oauth, oauth-plugin, and camping-oauth. Also we will require the various files we need: oauth, oauth\/server, oauth\/request_proxy, oauth\/request_proxy\/rack_request, camping-oauth, as well as the filtering_camping plugin.So now the top of the source should look like this:<\/p>\n<pre class=\"brush: ruby\">\r\ngem 'camping' , '>= 2.0'\t\r\ngem 'filtering_camping'\r\ngem 'oauth'\r\ngem 'oauth-plugin'\r\n\r\n%w(rubygems active_record camping camping\/session markaby json erb\r\noauth\r\noauth\/server\r\noauth\/request_proxy\r\noauth\/request_proxy\/rack_request\r\nfiltering_camping\r\ncamping-oauth\r\n).each { |lib| require lib }\r\n\r\nCamping.goes :CampingOAuthProvider\r\n<\/pre>\n<p>\t\t\t\t\t<a name='caoatodob'><\/a><\/p>\n<h5>B.Customizing the main module<\/h5>\n<p>Ok, so now we&#8217;re ready to enhance the main app module. First we&#8217;ll make sure to include the Camping::Session and CampingFilters modules, and to extend the app module with OAuthCampingPlugin, like so:<\/p>\n<pre class=\"brush: ruby\">\r\nmodule CampingOAuthProvider\r\n\tinclude Camping::Session\r\n\tinclude CampingFilters\r\n\textend  OAuthCampingPlugin\r\n\t\r\n\t# ...\r\nend\r\n<\/pre>\n<p>This gives us the ability to leverage a logger for the <a href='#tacaoa'>camping-oauth plugin<\/a>.<\/p>\n<pre class=\"brush: ruby\">\r\n\tOAuthCampingPlugin.logger = Logger.new(File.dirname(__FILE__) + '\/CampingOAuthProvider.log');\r\n\tOAuthCampingPlugin.logger.level = Logger::DEBUG\r\n<\/pre>\n<p>Now let&#8217;s customize the create method by adding a call to OAuthCampingPlugin.create, so we can give the plugin to run any needed initialization.<\/p>\n<pre class=\"brush: ruby\">\r\n\tdef CampingOAuthProvider.create\r\n\t\tOAuthCampingPlugin.create\r\n\tend\r\n<\/pre>\n<p>Ok, at this point we have a minimally configured application module. Our next step is to move on to the Models module.<\/p>\n<p>\t\t\t\t\t<a name='caoatodoc'><\/a><\/p>\n<h5>C.Plugging in the OAuth models<\/h5>\n<p>First, we&#8217;ll include the include OAuthCampingPlugin::Models module so we can get all the <a href='#oamo'>OAuth-specific models<\/a>. Then we&#8217;ll define a <a href='#oaus'>User<\/a> model. The User will need to keep track of the <a href='#oaca'>client applications<\/a> it provided access to. It will also manage the <a href='#oatn'>tokens<\/a> associated with these applications. Our model will look like this:<\/p>\n<pre class=\"brush: ruby\">\r\nclass User < Base;\r\n\thas_many :client_applications\r\n\thas_many :tokens, \r\n\t\t:class_name=>\"OauthToken\",\r\n\t\t:order=>\"authorized_at desc\",\r\n\t\t:include=>[:client_application]\r\n\r\nend\r\n<\/pre>\n<p>Now we need a CreateUserSchema migration class to define our database tables for User, and <a href='#oamo'>OAuth models<\/a>. In the up and down methods we will plugin a call to the corresponding method from the OAuthCampingPlugin::Models module to create the tables for <a href='#oaca'>ClientApplication<\/a>, <a href='#oatn'>OAuthToken<\/a>, and <a href='#oane'>OauthNonce<\/a>.<\/p>\n<pre class=\"brush: ruby\">\r\nclass CreateUserSchema < V 1.0\r\n\tdef self.up\r\n\t\tcreate_table :CampingOAuthProvider_users, :force => true do |t|\r\n\t\t\tt.integer \t:id, :null => false\r\n\t\t\tt.string\t\t:username\r\n\t\t\tt.string\t\t:password\r\n\t\tend\r\n\t\t\r\n\t\tUser.create :username => 'admin', :password => 'camping'\r\n\t\t\r\n\t\tOAuthCampingPlugin::Models.up\r\n\tend\r\n\t\r\n\tdef self.down\t\t\r\n\t\tOAuthCampingPlugin::Models.down\r\n\t\tdrop_table :CampingOAuthProvider_users\r\n\tend\r\nend\r\n<\/pre>\n<p>At this point we can go back to the main module and add the code to configure the ActiveRecord connection and invoke our new schema migration if the <a href='#oaus'>User<\/a> table does not exist yet. This code will be added to the create method:<\/p>\n<pre class=\"brush: ruby\">\r\nmodule CampingOAuthProvider\r\n\t# ...\t\r\n\r\n\tdef CampingOAuthProvider.create\r\n\t\tdbconfig = YAML.load(File.read('config\/database.yml'))\t\t\t\t\t\t\t\r\n\t\tCamping::Models::Base.establish_connection  dbconfig['development']\t\t\r\n\t\t\r\n\t\tOAuthCampingPlugin.create\r\n\t\t\r\n\t\tCampingOAuthProvider::Models.create_schema :assume => (CampingOAuthProvider::Models::User.table_exists? ? 1.1 : 0.0)\r\n\tend\r\nend\r\n<\/pre>\n<p>You probably noticed that the database configuration is loaded from a database.yml file. So let&#8217;s create a subfolder named config and a file named <b>database.yml<\/b>, then let&#8217;s configure the yaml file as follows:<\/p>\n<pre class=\"brush: ruby\">\r\ndevelopment:\r\n  adapter: sqlite3\r\n  database: campingoauthprovider.db\r\n<\/pre>\n<p>Now if we restart the application, our migration should be executed:<\/p>\n<p>\t\t\t\t\t<img src='.\/wp-content\/media\/camping-oauth-provider\/camping-oauth-provider-migration.png' width='570px'\/><\/p>\n<p>\t\t\t\t\t<a name='caoatodod'><\/a><\/p>\n<h5>D.Creating a common helpers module<\/h5>\n<p>The Helpers module is used in <a href='#rc'>Camping<\/a> to provide common utilities to both the Controllers and Views modules. Enhancing our Helpers module is very easy, we need to add both and extend and an include of the OAuthCampingPlugin::Helpers module so we can enhance both instance and class sides:<\/p>\n<pre class=\"brush: ruby\">\r\nmodule CampingOAuthProvider::Helpers\r\n\textend OAuthCampingPlugin::Helpers\r\n\tinclude OAuthCampingPlugin::Helpers\r\nend<\/pre>\n<p>\t\t\t\t\t<a name='caoatodoe'><\/a><\/p>\n<h5>E.Plugging in the OAuth controllers<\/h5>\n<p>We will need to extend our app <b>Controllers<\/b> module with the <b>OAuthCampingPlugin::Controllers<\/b> module using the extend statement. Then just before the end of the Controllers module, we&#8217;ll add a call to the <b>include_oauth_controllers<\/b> method. This is how <a href='#tacaoa'>camping-oauth<\/a> will inject and plugin the common OAuth controllers and helpers. It is important that this call <u>always remaining the last statement of the module<\/u>, even when you add new controller classes. So the module should look like so:<\/p>\n<pre class=\"brush: ruby\">\r\nmodule CampingOAuthProvider::Controllers\r\n\textend OAuthCampingPlugin::Controllers\r\n\r\n\t# ...\r\n\r\n\tinclude_oauth_controllers\r\nend #Controllers\r\n<\/pre>\n<p>Before we continue fleshing out the logic of our controllers, let&#8217;s finish hooking up the Views module.<\/p>\n<p>\t\t\t\t\t<a name='caoatodof'><\/a><\/p>\n<h5>F.Plugging in the OAuth common views<\/h5>\n<p>We will need to extend our app <b>Views<\/b> module with the <b>OAuthCampingPlugin::Views<\/b> module using the extend statement. Then just before the end of the Views module, we&#8217;ll add a call to the <b>include_oauth_views<\/b> method. This is how <a href='#tacaoa'>camping-oauth<\/a> will inject and plugin the common OAuth views. It is important that this call <u>always remaining the last statement of the module<\/u>, even when you add new view methods. So the module should look like so:<\/p>\n<pre class=\"brush: ruby\">\r\nmodule CampingOAuthProvider::Views\r\n\textend OAuthCampingPlugin::Views\r\n\r\n\t# ...\r\n\t\r\n\tinclude_oauth_views\r\nend\r\n<\/pre>\n<p>\t\t\t\t\t<a name='caoatodog'><\/a><\/p>\n<h5>G.Adding basic login and registration capabilities<\/h5>\n<p>Let&#8217;s add a Login controller class to our Controllers module:<\/p>\n<pre class=\"brush: ruby\">\r\n\tclass Login < R '\/login'\t\t\t\r\n\t\tdef get\r\n\t\t\trender :login\r\n\t\tend\r\n\t\t\r\n\t\tdef post\r\n\t\t\t@user = User.find_by_username_and_password(input.username, input.password)\r\n\r\n\t\t\tif @user\r\n\t\t\t\t@state.user_id = @user.id\r\n\r\n\t\t\t\tif @state.return_to.nil?\r\n\t\t\t\t\tredirect R(Index)\r\n\t\t\t\telse\r\n\t\t\t\t\treturn_to = @state.return_to\r\n\t\t\t\t\t@state.return_to = nil\r\n\t\t\t\t\tredirect(return_to)\r\n\t\t\t\tend\r\n\t\t\telse\r\n\t\t\t\t@info = 'Wrong username or password.'\r\n\t\t\tend\r\n\t\t\trender :login\t\t\r\n\t\tend\r\n\tend\r\n<\/pre>\n<p>And now add the corresponding login view in the Views module\"<\/p>\n<pre class=\"brush: ruby\">\r\n\tdef login\r\n\t\tdiv @info if @info\r\n\t\tform :action => R(Login), :method => 'post' do\r\n\t\t\tlabel 'Username', :for => 'username'; br\r\n\t\t\tinput :name => 'username', :type => 'text'; br\r\n\r\n\t\t\tlabel 'Password', :for => 'password'; br\r\n\t\t\tinput :name => 'password', :type => 'text'; br\r\n\r\n\t\t\tinput :type => 'submit', :name => 'login', :value => 'Login'\r\n\t\tend\r\n\tend\r\n<\/pre>\n<p>Let's verify we can login by accessing the following url:<\/p>\n<pre class=\"brush: ruby\">\r\nhttp:\/\/localhost:3301\/login\r\n<\/pre>\n<p>Now that login support is in place you can test out one of the OAuth controllers by navigating to the following url:<\/p>\n<pre class=\"brush: ruby\">\r\nhttp:\/\/localhost:3301\/oauth\/register\r\n<\/pre>\n<p>Since the <a href='#tacaoa'>camping-oauth plugin<\/a> installed a :before filter on the OAuthRegisterApplication controller requiring user login, you should be redirected first to the login page.<br \/>\n\t\t\t\t\tSince we created a default account when running the migration, login as <b>admin<\/b> with <b>camping<\/b> as the password. Once logged in you should be redirected back to the OAuth Application Registration page.<\/p>\n<p>\t\t\t\t\t<img src='.\/wp-content\/media\/camping-oauth-provider\/camping-oauth-provider-app-reg.png'  width='200px'  style='margin-left: 50px;'><\/p>\n<p>As a side note, you can style all common OAuth views later using CSS.<br \/>\n\t\t\t\t\tWe'll let you add the SignUp controller and its signup view on your own.<\/p>\n<p>\t\t\t\t\t<a name='caoatodoh'><\/a><\/p>\n<h5>H.Adding our custom API, protected by OAuth<\/h5>\n<p>Since the premise of this post was to make it easy for web apps to consume an OAuth-protected service, let's create a very simple controller (no view needed) to expose some data as JSON.<\/p>\n<pre class=\"brush: ruby\">\r\n\tclass APITimeNow < R '\/api\/timenow'\r\n\t\tdef get\r\n\t\t\t@result = {:now=>Time.now.utc.to_s}\r\n\t\t\t@result[:username] = @user.username if @user\r\n\t\t\t\r\n\t\t\t@headers['Content-Type'] = \"application\/json\"\r\n\t\t\tlog_debug @result.to_json\r\n\t\t\t@result.to_json\r\n\t\tend\r\n\tend\r\n<\/pre>\n<p>Now we can test it by navigating to the following url (after installing the <a href='#jsnvw'>JSONview<\/a> plugin for FireFox to make it easier to see the returned JSON data):<\/p>\n<pre class=\"brush: ruby\">\r\nhttp:\/\/localhost:3301\/api\/timenow\r\n<\/pre>\n<p><img src='.\/wp-content\/media\/camping-oauth-provider\/camping-oauth-provider-api.png'  \/><br \/>\n\t\t\t\t\tNote that at this point this controller is NOT YET protected by OAuth. For that we need to declare a before filter for the APITimeNow controller requiring to be either logged in or OAuth-authenticated. So let's add this code snippet to our main module:<\/p>\n<pre class=\"brush: ruby\">\r\nmodule GatedCampingSite\r\n\t# ...\r\n\t\r\n\tbefore [:APITimeNow] do\r\n\t\tlogin_or_oauth_required\r\n\tend\r\n\t\r\n\t# ...\r\nend\t\r\n<\/pre>\n<p>So now if we logged out (by deleting the session cookies since we have not implemented logoff) and refreshed our browser we would be redirected to the login page.<\/p>\n<h3>Testing And Troubleshooting<\/h3>\n<p>At this stage, we have a basic Camping OAuth provider, now let's test it! The first thing is to register a new OAuth consumer named camping-oauth-consumer. We'll assume that:<\/p>\n<ol>\n<li>it is located at http:\/\/localhost:3000\/ (fictitious for now)<\/li>\n<li>it exposes a url: http:\/\/localhost:3000\/callback to accept an <a href='#oaat'>OAuth Access token<\/a> <a href='#oave'>verifier<\/a> once authorized<\/li>\n<\/ol>\n<p><img src='.\/wp-content\/media\/camping-oauth-provider\/camping-oauth-provider-reg1.png'   width='200px'  style='margin-left: 50px;'><br \/>\n\t\t\t\t\tOnce you register you should see the following results page:<\/p>\n<p>\t\t\t\t\t<img src='.\/wp-content\/media\/camping-oauth-provider\/camping-oauth-provider-reg2.png'   width='350px'  style='margin-left: 50px;'><br \/>\n\t\t\t\t\tThe key and secret will be used by our consumer as credentials when accessing our OAuth provider, so copy\/paste them into a notepad. <br \/>\n\t\t\t\t\tHere is what has been stored in our SQLite database:<\/p>\n<p>\t\t\t\t\t<img src='.\/wp-content\/media\/camping-oauth-provider\/camping-oauth-provider-reg3.png' width='540px' ><br \/>\n\t\t\t\t\t<i>Note: if you are interested in <a href='#lita'>Lita<\/a>, an AIR-based SQLite administration tool, see <a href='#lita'>here<\/a>.<\/i><\/p>\n<p>For our first test consumer will use IRB, so open up a session and let's define 3 variables for: url of our provider, key and secret (use your own values) of our registered consumer:<\/p>\n<pre class=\"brush: ruby\">\r\n@site={:site=>\"http:\/\/localhost:3301\"}\r\n@mykey=\"SQnIXDQyhFB5q3wfZyMY\"\r\n@mysecret=\"PmW02FNs7rXG97sAVXMWhFoJVZ98cnj21vv6p1ad\"\r\n<\/pre>\n<p>Now let's require oauth and let's instantiate an OAuth consumer:<\/p>\n<pre class=\"brush: ruby\">\r\nrequire 'oauth'\r\n@consumer = OAuth::Consumer.new(@mykey,@mysecret,@site)\r\n<\/pre>\n<p>You should get an instance back:<\/p>\n<p>\t\t\t\t\t<img src='.\/wp-content\/media\/camping-oauth-provider\/camping-oauth-provider-ico.png' width='540px'>\n\t\t\t\t\t<\/p>\n<p>Our next step is to request an OAuth <a href='#oart'>RequestToken<\/a> like so:<\/p>\n<pre class=\"brush: ruby\">\r\n@request_token = @consumer.get_request_token\t\t\t\t\t\r\n<\/pre>\n<p>You should get a <a href='#oart'>request token<\/a> back:<\/p>\n<p>\t\t\t\t\t<img src='.\/wp-content\/media\/camping-oauth-provider\/camping-oauth-provider-rt.png' width='540px'>\n\t\t\t\t\t<\/p>\n<p>Let's see how and where we should authorize this <a href='#oart'>request token<\/a>:<\/p>\n<pre class=\"brush: ruby\">\r\n@request_token.authorize_url\t\t\t\t\t\r\n<\/pre>\n<p>You should get back the url to authorize the specific <a href='#oart'>request token<\/a> you just obtained.<\/p>\n<p>\t\t\t\t\t<img src='.\/wp-content\/media\/camping-oauth-provider\/camping-oauth-provider-rtu.png' width='540px'>\n\t\t\t\t\t<\/p>\n<p>So let's copy this url and let's paste it back in the browser:<\/p>\n<pre class=\"brush: ruby\">\r\nhttp:\/\/localhost:3301\/oauth\/authorize?oauth_token=0Qd6g3SjWHQEM6sUTcd9\t\t\r\n<\/pre>\n<p>We should be prompted by the OAuth Authorization controller of our provider:<\/p>\n<p>\t\t\t\t\t<img src='.\/wp-content\/media\/camping-oauth-provider\/camping-oauth-provider-auth.png'   width='299px'  style='margin-left: 50px;'><\/p>\n<p>If you click on the checkbox and the Authorize button, the provider will redirect you to the callback url we defined during registration passing back the Oauth token id and and a <a href='#oave'>verifier<\/a> code. Since we don't have a consumer web app up and running, we will get a navigation error. Here is what the target (redirection) url looks like:<\/p>\n<pre class=\"brush: ruby\">\r\nhttp:\/\/localhost:3000\/callback?oauth_token=0Qd6g3SjWHQEM6sUTcd9&oauth_verifier=71Jt3GhiwvHlZYO9zA8c\t\t\r\n<\/pre>\n<p>This <a href='#oave'>verifier<\/a> acts as a sort of session id we need to pass to get an OAuth <a href='#oaat'>Access Token<\/a>. So from our IRB session, let's evaluate the following statement:<\/p>\n<pre class=\"brush: ruby\">\r\n@verifier = '71Jt3GhiwvHlZYO9zA8c'\r\n@access_token = @request_token.get_access_token(:oauth_verifier=>@verifier)\r\n<\/pre>\n<p>You should get an <a href='#oaat'>access token<\/a> back:<\/p>\n<p>\t\t\t\t\t<img src='.\/wp-content\/media\/camping-oauth-provider\/camping-oauth-provider-at.png' width='540px'>\n\t\t\t\t\t<\/p>\n<p>So now let's call our provider api:<\/p>\n<pre class=\"brush: ruby\">\r\n@response = @access_token.get('\/api\/timenow')\r\n@info = @response.body\r\n<\/pre>\n<p>You should get back a json object:<\/p>\n<p>\t\t\t\t\t<img src='.\/wp-content\/media\/camping-oauth-provider\/camping-oauth-provider-atr.png' width='540px'><br \/>\n\t\t\t\t\tYippee!!!\n\t\t\t\t\t<\/p>\n<p><\/p>\n<h5>Recap<\/h5>\n<p>So this concludes our whirlwind tour of <a href='#oawp'>OAuth<\/a> from a provider and consumer side. I am leaving the following enhancements for you to do on your own:<\/p>\n<ol>\n<li>provider logout<\/li>\n<li>provider user registration<\/li>\n<li>provider view of all registered applications for a given user<\/li>\n<li>provider view of all tokens for a given user's registered application<\/li>\n<li>consumer sample web app<\/li>\n<li>consumer callback route<\/li>\n<\/ol>\n<p>Also if you look in the examples folder of the <a href='#tacaoa'>camping-oauth<\/a> gem you will find the full source for both a provider (the one we have been working on) and a consumer app (to be run on port 3302).<\/p>\n<h3>So What? <\/h3>\n<ol>\n<li><a href='#oawp'>OAuth<\/a> has become a key enabler in authorizing data sharing across web sites. <a href='#oawp'>OAuth<\/a> also \"plays nice\" with identity and authentication solutions such as for example OpenID.<br \/>&nbsp;<\/li>\n<li>Ruby and <a href='#rc'>Camping<\/a> make it very easy to develop web applications and web services (whether you support JSON, XML, with or without REST).<br \/>\n\t\t\t\t\t\t<i>Note: if you're interested in REST support for Camping web services check out <a href='http:\/\/github.com\/camping\/reststop'>RESTstop<\/a>.<\/i><br \/>&nbsp;<\/li>\n<li>With the <a href='#tacaoa'>camping-oauth plugin<\/a> you can easily and quickly allow your services or web app to be accessed from other services.<\/li>\n<\/ol>\n<p>So hopefully this post will have given you a feel for how easy it is to make a Ruby <a href='#rc'>Camping<\/a>-based web app act as an <a href='#oa'>OAuth provider<\/a> using the <a href='#tacaoa'>Camping OAuth plugin<\/a>.<\/p>\n<p>\t\t\t\t\tHappy OAuth experimentations!!!<\/p>\n<p><img src='http:\/\/hueniverse.com\/wp-content\/uploads\/2007\/12\/My-Endpoints.png' title='Cartoon from the hueniverse.com site' \/><\/p>\n<p>\t\t\t\t\t<a name=\"referencesandresources\" ><\/a><\/p>\n<h3>References and Resources<\/h3>\n<h5>OAuth<\/h5>\n<ul>\n<li><a name='oawp' href='http:\/\/en.wikipedia.org\/wiki\/Oauth'>OAuth Definition on Wikipedia<\/a><\/li>\n<li><a name='oaspec1a' href='http:\/\/oauth.net\/core\/1.0a\/'>OAuth Core 1.0a<\/a><\/li>\n<li><a name='oapr' href='http:\/\/wiki.oauth.net\/ServiceProviders'>OAuth Providers Catalog<\/a><\/li>\n<li><a name='oan' href='http:\/\/oauth.net\/'>OAuth.net site<\/a><\/li>\n<li><a name='oau' href='http:\/\/hueniverse.com\/'>OAuth Universe site<\/a><\/li>\n<li><a name='oarb' href='http:\/\/oauth.rubyforge.org\/'>OAuth Ruby repository on GitHub<\/a><\/li>\n<li><a name='oarails' href='http:\/\/stakeventures.com\/articles\/2007\/11\/26\/how-to-turn-your-rails-site-into-an-oauth-provider\/'>How to turn your rails site into an OAuth Provider<\/a><\/li>\n<p><\/a><\/li>\n<li><a name='oaspec2' href='https:\/\/svn.tools.ietf.org\/html\/draft-hammer-oauth2-00'>Upcoming OAuth 2.0 Protocol<\/a><\/li>\n<\/ul>\n<h5>Camping<\/h5>\n<ul>\n<li><a name='rc' href='http:\/\/github.com\/camping\/camping'>Ruby Camping Framework<\/a><\/li>\n<li><a name='tacaoa' href='http:\/\/github.com\/techarch\/camping-oauth'>Camping-OAuth repository on GitHub<\/a><\/li>\n<li><a name='tacaoa' 'http:\/\/github.com\/camping\/reststop'>Camping RESTstop framework on GitHub<\/a><\/li>\n<\/ul>\n<p>\t\t\t\t\t<a name=\"contributors\" ><\/a><\/p>\n<h5>Contributors\/Ruby-ists<\/h5>\n<ul>\n<li><a name='jf' href='http:\/\/judofyr.net\/'>Magnus Holm (@judofyr) - Camping, ...<\/a><\/li>\n<li><a name='pb' href='http:\/\/stakeventures.com\/'>Pelle Braendgaard (@pelleb) - OAuth, ...<\/a><\/li>\n<\/ul>\n<p>\t\t\t\t\t<a name=\"metaprog\" ><\/a><\/p>\n<h5>Metaprogramming<\/h5>\n<ul>\n<li><a name='inex' href='http:\/\/railstips.org\/blog\/archives\/2009\/05\/15\/include-vs-extend-in-ruby\/'>Include vs. Extend in Ruby (by John Nunemaker)<\/a><\/li>\n<li><a name='momi' href='http:\/\/ruby-doc.org\/docs\/ProgrammingRuby\/html\/tut_modules.html#S2'>[Module] Mixins (in Programming Ruby)<\/a><\/li>\n<li><a name='clex' href='http:\/\/ruby-doc.org\/docs\/ProgrammingRuby\/html\/classes.html#UD'>Extending Objects (in Programming Ruby)<\/a><\/li>\n<li><a name='moev' href='http:\/\/www.ruby-doc.org\/docs\/ProgrammingRuby\/ref_c_module.html#Module.module_eval'>Adding module behavior with module_eval (in Programming Ruby)<\/a><\/li>\n<li><a name='iece' href='http:\/\/bmorearty.wordpress.com\/2009\/01\/09\/fun-with-rubys-instance_eval-and-class_eval\/'>Fun with Ruby\u2019s instance_eval and class_eval (by Brian Morearty)<\/a><\/li>\n<\/ul>\n<h5>OAuth Integrations<\/h5>\n<ul>\n<li><a name='oagg' href='http:\/\/code.google.com\/apis\/accounts\/docs\/OAuth.html'>Google OAuth for Web Applications<\/a><\/li>\n<li><a name='oatw' href='http:\/\/apiwiki.twitter.com\/Authentication'>Twitter OAuth<\/a><\/li>\n<li><a name='oanf' href='http:\/\/developer.netflix.com\/docs\/Security'>NetFlix OAuth<\/a><\/li>\n<\/ul>\n<h5>Tools<\/h5>\n<ul>\n<li><a name='jsnvw' href='https:\/\/addons.mozilla.org\/en-US\/firefox\/addon\/10869\/?src=api'>JSONview plugin for FireFox<\/a><\/li>\n<li><a name='oadan' href='http:\/\/github.com\/episod\/oauth-dancer'>Taylor Singletary's (@episod) OAuth Dancer Tool<\/a><\/li>\n<li><a name='lita' \thref='http:\/\/www.dehats.com\/drupal\/?q=node\/58'>Lita, a SQLite administration tool<\/a><\/li>\n<li><a name='tcpt' \thref='http:\/\/www.pocketsoap.com\/tcptrace\/'>TCP Trace<\/a><\/li>\n<\/ul>\n<h5>My Other Related Posts:<\/h5>\n<ul name=\"myotherrelatedposts\">\n<li><a href='https:\/\/blog.monnet-usa.com\/?p=288'>Camping light (nosql) with MongoDB<\/a><\/li>\n<li><a href='https:\/\/blog.monnet-usa.com\/?p=223'>Visualize Application Metrics on NewRelic for your Ruby Camping Application<\/a><\/li>\n<li><a href='https:\/\/blog.monnet-usa.com\/?p=166'>Running the Camping Microframework on IronRuby<\/a><\/li>\n<\/ul>\n<p>\t\t\t\t\t<a name='oacasrc'><\/a><\/p>\n<h5>Source Code<\/h5>\n<div   class='download_panel'>All source is available on GitHub:<\/p>\n<ul>\n\t\t\t\t\t\t<a href='http:\/\/bit.ly\/campingoauth'>Camping OAuth <b>Plugin<\/b> library<\/a><br \/>\n\t\t\t\t\t\t<a href='http:\/\/bit.ly\/cgoapreg'>Camping OAuth <b>Provider<\/b> Example<\/a><br \/>\n\t\t\t\t\t\t<a href='http:\/\/bit.ly\/cgoacoeg'>Camping OAuth <b>Consumer<\/b> Example<\/a>\n\t\t\t\t\t<\/div>\n","protected":false},"excerpt":{"rendered":"<p>Intro Over the last year OAuth or Open Authorization has really been gaining ground as a mechanism to open up\/free your data hosted on various web sites and let you share that data across sites. The surge in interest can be attributed to a couple developments: Wider availability of OAuth libraries on a wide array [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[35,3,28],"tags":[23,62,56],"class_list":["post-293","post","type-post","status-publish","format-standard","hentry","category-oauth","category-ruby","category-ruby-camping","tag-camping","tag-oauth","tag-ruby"],"_links":{"self":[{"href":"https:\/\/blog.monnet-usa.com\/index.php?rest_route=\/wp\/v2\/posts\/293","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blog.monnet-usa.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.monnet-usa.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.monnet-usa.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.monnet-usa.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=293"}],"version-history":[{"count":4,"href":"https:\/\/blog.monnet-usa.com\/index.php?rest_route=\/wp\/v2\/posts\/293\/revisions"}],"predecessor-version":[{"id":297,"href":"https:\/\/blog.monnet-usa.com\/index.php?rest_route=\/wp\/v2\/posts\/293\/revisions\/297"}],"wp:attachment":[{"href":"https:\/\/blog.monnet-usa.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=293"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.monnet-usa.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=293"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.monnet-usa.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=293"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}