{"id":6953,"date":"2017-09-18T09:45:58","date_gmt":"2017-09-18T16:45:58","guid":{"rendered":"https:\/\/www.backerkit.com\/blog\/?p=6953"},"modified":"2020-02-21T00:40:42","modified_gmt":"2020-02-21T08:40:42","slug":"using-rails-messageverifier-for-stateless-token-management","status":"publish","type":"post","link":"https:\/\/www.backerkit.com\/blog\/using-rails-messageverifier-for-stateless-token-management\/","title":{"rendered":"Using Rails&#8217; MessageVerifier for Stateless Token Management"},"content":{"rendered":"<span class=\"cb-itemprop\" itemprop=\"reviewBody\"><p>Many web applications have the need to send links to users that allow the user to perform an action without logging in. Examples include password reset and confirming an email address. These links need to embed some kind of identifying information so the server can discern which user is performing the action. If the action is sensitive, the link should also include some amount of obfuscation so the URLs cannot be guessed or generated by nefarious actors.<\/p>\n<p>We have a few ways to generate links that serve this purpose. Many applications start with something like Rails&#8217; <a href=\"https:\/\/github.com\/rails\/rails\/pull\/18217\">has&#95;secure_token<\/a>. This helper wraps up the logic to generate and persist tokens in a datastore. This approach is well understood and easy to reason about.<\/p>\n<p>What are some of the downsides of storing tokens on the server? Storing the tokens in plaintext means if an attacker gets access to the application&#8217;s database, all of the stored tokens are exposed. Hashing (or digesting) the tokens asymmetrically fixes this issue but we still have to persist and protect this data.<\/p>\n<p>What if we don&#8217;t need to persist the token at all? What if we could generate a token, send it out in a link, and then verify it when it gets sent back to us? In this way, we don&#8217;t have to store the tokens, which means there is less to protect.<\/p>\n<p>We can achieve this stateless approach with encoded and signed tokens. Rails provides a mechanism to generate and verify tokens via <a href=\"http:\/\/api.rubyonrails.org\/classes\/ActiveSupport\/MessageEncryptor.html\"><code>ActiveSupport::MessageEncryptor<\/code><\/a> and <a href=\"http:\/\/api.rubyonrails.org\/classes\/ActiveSupport\/MessageVerifier.html\"><code>ActiveSupport::MessageVerifier<\/code><\/a>.<\/p>\n<p>We recently implemented stateless tokens in our app so users could confirm subscriptions to mailing lists. Below we&#8217;ll go through some code to get us there.<\/p>\n<h2>Let&#8217;s look at some code<\/h2>\n<p>We have a controller with a <code>create<\/code> action that allows a user to submit an email address and a <code>confirmations<\/code> action that verifies a submitted token.<\/p>\n<pre><code>class SubscriptionsController &lt; ApplicationController\n  def create\n    subscription = Subscription.build(email: subscription_params[:email])\n\n    if subscription.save\n      SubscriptionsMailer.confirm_subscription(subscription.id).deliver_later  \n      redirect_to subscriptions_path\n    else\n      redirect_to subscriptions_path\n    end\n  end\n\n  def confirmations\n    subscription = Subscription.verify_token_and_find(token: params[:token])\n\n    if subscription.present?\n      subscription.touch(:confirmed_at)\n      flash[:notice] = \"Thanks for subscribing!\"\n    else\n      flash[:error] = \"Oh no! Your token is not valid.\"\n    end\n\n    redirect_to subscriptions_path\n  end\n\n  private\n\n  def subscription_params\n    params.require(:subscription).permit(:email)\n  end\nend\n<\/code><\/pre>\n<p>And our model looks like this:<\/p>\n<pre><code>class Subscription &lt; ApplicationRecord\n  CONFIRMATION_IN_DAYS = 7\n  scope :confirmed, lambda { where.not(confirmed_at: nil) }\n  validates :email, uniqueness: true\n\n  def generate_token(expiration_in_days: CONFIRMATION_IN_DAYS)\n    expiration = Time.current + expiration_in_days.days\n    token_values = { id: id, expiration: expiration }\n    self.class.encryptor.encrypt_and_sign(token_values)\n  end\n\n  def self.verify_token_and_find(token:)\n    begin\n      data = encryptor.decrypt_and_verify(token)\n      given_expiration = data[:expiration]\n\n      if given_expiration &lt; Time.current\n        return nil\n      end\n\n      find(data[:id])\n    rescue ActiveSupport::MessageVerifier::InvalidSignature\n      nil\n    end\n  end\n\n  def self.encryptor\n    key_password_for_mailing_list = ENV.fetch('KEY_PASSWORD_FOR_SUBSCRIPTION')\n    SUBSCRIPTION_ENCRYPTOR_KEY = ActiveSupport::KeyGenerator\n      .new(key_password_for_mailing_list)\n      .generate_key(salt, 32)\n\n    ActiveSupport::MessageEncryptor.new(SUBSCRIPTION_ENCRYPTOR_KEY)\n  end\nend\n<\/code><\/pre>\n<p>Our mailer is relatively straightforward except for the line where we call <code>subscription.generate_token<\/code>, which does the heavy lifting for generating and signing our token:<\/p>\n<pre><code>class SubscriptionsMailer &lt; ActionMailer::Base\n  def confirm_subscription(subscription_id)\n    subscription = Subscription.find(subscription_id)\n    @link = confirmation_url(subscription: subscription)\n\n    mail(\n      from: \"support@yourwebsite.com\",\n      subject: \"Please Confirm Your Subscription\",\n      to: subscription.email\n    ) do |format|\n      format.text\n      format.html\n    end\n  end\n\n  private\n\n  def confirmation_url(subscription:)\n    subscriptions_url(token: subscription.generate_token)\n  end\nend\n<\/code><\/pre>\n<h2>What&#8217;s the catch?<\/h2>\n<p>One downside of this approach is the need to manage another key, which involves protecting it (likely via using environment variables) and being able to rotate the key in an operationally simple manner. There is not a great option out of the box to manage these workflows but it&#8217;s worth considering the costs and benefits of not storing this data.<\/p>\n<h2>Conclusion<\/h2>\n<p>We wanted to find a way to avoid storing keys in our database for security and storage reasons and this approach serves our purpose. Expiring, rotating, and protecting keys still require forethought, but that&#8217;s nothing new.<\/p>\n<h2>Want to learn more?<\/h2>\n<ul>\n<li><a href=\"https:\/\/www.youtube.com\/watch?v=s7G2VnuMVEw\">This RailsConf talk<\/a> has a nice overview of thinking in stateless terms<\/li>\n<li>Check out <a href=\"https:\/\/github.com\/rails\/rails\/blob\/master\/activesupport\/lib\/active_support\/message_verifier.rb\">the source code<\/a><\/li>\n<li>Read these <a href=\"http:\/\/www.monkeyandcrow.com\/blog\/reading_rails_how_does_message_verifier_work\/\">blog<\/a> <a href=\"http:\/\/www.monkeyandcrow.com\/blog\/reading_rails_how_does_message_encryptor_work\/\">posts<\/a> for a more in depth overview of using these tools<\/li>\n<li>If this stuff is interesting to you and you&#8217;d like to chat, drop us a line: <a href=\"&#x6d;&#97;i&#x6c;&#116;o&#x3a;&#101;&#110;&#x67;&#105;&#110;&#x65;&#101;&#114;&#x69;&#x6e;&#103;&#x40;&#x62;&#97;&#x63;&#x6b;&#101;&#x72;&#x6b;&#105;t&#x2e;&#99;o&#x6d;\">&#101;&#110;&#x67;&#105;&#110;&#x65;&#101;&#114;&#x69;&#x6e;&#103;&#x40;&#x62;&#97;&#x63;&#x6b;&#101;&#x72;&#x6b;&#105;t&#x2e;&#99;o&#x6d;<\/a><\/li>\n<\/ul>\n<\/span>","protected":false},"excerpt":{"rendered":"<p>Many web applications have the need to send links to users that allow the user to perform an action without logging in. Examples include password reset and confirming an email address. These links need to embed some kind of identifying information so the server can discern which user is performing the action. If the action [&hellip;]<\/p>\n","protected":false},"author":20,"featured_media":7089,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[45],"tags":[],"class_list":["post-6953","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-engineering"],"acf":[],"yoast_head":"\n<title>Using Rails&#039; MessageVerifier for Stateless Token Management | BackerKit<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.backerkit.com\/blog\/using-rails-messageverifier-for-stateless-token-management\/\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:title\" content=\"Using Rails&#039; MessageVerifier for Stateless Token Management | BackerKit\" \/>\n<meta name=\"twitter:description\" content=\"Many web applications have the need to send links to users that allow the user to perform an action without logging in. Examples include password reset and confirming an email address. These links need to embed some kind of identifying information so the server can discern which user is performing the action. If the action [&hellip;]\" \/>\n<meta name=\"twitter:image\" content=\"https:\/\/www.backerkit.com\/blog\/wp-content\/uploads\/2017\/09\/Using-Rails-MessageVerifier-for-Stateless-Token-Management.png\" \/>\n<meta name=\"twitter:creator\" content=\"@simontaranto\" \/>\n<meta name=\"twitter:site\" content=\"@backerkit\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Simon Taranto\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"4 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/www.backerkit.com\/blog\/using-rails-messageverifier-for-stateless-token-management\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/www.backerkit.com\/blog\/using-rails-messageverifier-for-stateless-token-management\/\"},\"author\":{\"name\":\"Simon Taranto\",\"@id\":\"https:\/\/www.backerkit.com\/blog\/#\/schema\/person\/860d1b2b8b38a20bce936391e5ed85de\"},\"headline\":\"Using Rails&#8217; MessageVerifier for Stateless Token Management\",\"datePublished\":\"2017-09-18T16:45:58+00:00\",\"dateModified\":\"2020-02-21T08:40:42+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/www.backerkit.com\/blog\/using-rails-messageverifier-for-stateless-token-management\/\"},\"wordCount\":511,\"publisher\":{\"@id\":\"https:\/\/www.backerkit.com\/blog\/#organization\"},\"image\":{\"@id\":\"https:\/\/www.backerkit.com\/blog\/using-rails-messageverifier-for-stateless-token-management\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.backerkit.com\/blog\/wp-content\/uploads\/2017\/09\/Using-Rails-MessageVerifier-for-Stateless-Token-Management.png\",\"articleSection\":[\"Engineering\"],\"inLanguage\":\"en-US\"},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/www.backerkit.com\/blog\/using-rails-messageverifier-for-stateless-token-management\/\",\"url\":\"https:\/\/www.backerkit.com\/blog\/using-rails-messageverifier-for-stateless-token-management\/\",\"name\":\"Using Rails' MessageVerifier for Stateless Token Management | BackerKit\",\"isPartOf\":{\"@id\":\"https:\/\/www.backerkit.com\/blog\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/www.backerkit.com\/blog\/using-rails-messageverifier-for-stateless-token-management\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/www.backerkit.com\/blog\/using-rails-messageverifier-for-stateless-token-management\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.backerkit.com\/blog\/wp-content\/uploads\/2017\/09\/Using-Rails-MessageVerifier-for-Stateless-Token-Management.png\",\"datePublished\":\"2017-09-18T16:45:58+00:00\",\"dateModified\":\"2020-02-21T08:40:42+00:00\",\"breadcrumb\":{\"@id\":\"https:\/\/www.backerkit.com\/blog\/using-rails-messageverifier-for-stateless-token-management\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/www.backerkit.com\/blog\/using-rails-messageverifier-for-stateless-token-management\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.backerkit.com\/blog\/using-rails-messageverifier-for-stateless-token-management\/#primaryimage\",\"url\":\"https:\/\/www.backerkit.com\/blog\/wp-content\/uploads\/2017\/09\/Using-Rails-MessageVerifier-for-Stateless-Token-Management.png\",\"contentUrl\":\"https:\/\/www.backerkit.com\/blog\/wp-content\/uploads\/2017\/09\/Using-Rails-MessageVerifier-for-Stateless-Token-Management.png\",\"width\":1558,\"height\":748},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/www.backerkit.com\/blog\/using-rails-messageverifier-for-stateless-token-management\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/www.backerkit.com\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Using Rails&#8217; MessageVerifier for Stateless Token Management\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/www.backerkit.com\/blog\/#website\",\"url\":\"https:\/\/www.backerkit.com\/blog\/\",\"name\":\"Crowdfunding Blog &amp; Resources | BackerKit\",\"description\":\"The BackerKit crowdfunding blog provides expert advice and success stories to help you plan, manage, and deliver a successful crowdfunding campaign.\",\"publisher\":{\"@id\":\"https:\/\/www.backerkit.com\/blog\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/www.backerkit.com\/blog\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/www.backerkit.com\/blog\/#organization\",\"name\":\"BackerKit\",\"url\":\"https:\/\/www.backerkit.com\/blog\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.backerkit.com\/blog\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/www.backerkit.com\/blog\/wp-content\/uploads\/2017\/02\/BackerKit-logo.png\",\"contentUrl\":\"https:\/\/www.backerkit.com\/blog\/wp-content\/uploads\/2017\/02\/BackerKit-logo.png\",\"width\":1200,\"height\":345,\"caption\":\"BackerKit\"},\"image\":{\"@id\":\"https:\/\/www.backerkit.com\/blog\/#\/schema\/logo\/image\/\"},\"sameAs\":[\"https:\/\/www.facebook.com\/Backerkit\/\",\"https:\/\/x.com\/backerkit\",\"https:\/\/www.instagram.com\/backerkit\/\",\"https:\/\/www.linkedin.com\/company\/backerkit\",\"https:\/\/www.youtube.com\/channel\/UC3gch2VsESfv0XW36W7BBQg\"]},{\"@type\":\"Person\",\"@id\":\"https:\/\/www.backerkit.com\/blog\/#\/schema\/person\/860d1b2b8b38a20bce936391e5ed85de\",\"name\":\"Simon Taranto\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.backerkit.com\/blog\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/90212df57bf38f6f4e9cc846a23e49e9b9e19e8a5b8c32d5d01ec4d2fbd8b227?s=96&d=monsterid&r=pg\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/90212df57bf38f6f4e9cc846a23e49e9b9e19e8a5b8c32d5d01ec4d2fbd8b227?s=96&d=monsterid&r=pg\",\"caption\":\"Simon Taranto\"},\"sameAs\":[\"http:\/\/www.backerkit.com\",\"https:\/\/x.com\/simontaranto\"],\"url\":\"https:\/\/www.backerkit.com\/blog\/author\/simon\/\"}]}<\/script>\n","yoast_head_json":{"title":"Using Rails' MessageVerifier for Stateless Token Management | BackerKit","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.backerkit.com\/blog\/using-rails-messageverifier-for-stateless-token-management\/","twitter_card":"summary_large_image","twitter_title":"Using Rails' MessageVerifier for Stateless Token Management | BackerKit","twitter_description":"Many web applications have the need to send links to users that allow the user to perform an action without logging in. Examples include password reset and confirming an email address. These links need to embed some kind of identifying information so the server can discern which user is performing the action. If the action [&hellip;]","twitter_image":"https:\/\/www.backerkit.com\/blog\/wp-content\/uploads\/2017\/09\/Using-Rails-MessageVerifier-for-Stateless-Token-Management.png","twitter_creator":"@simontaranto","twitter_site":"@backerkit","twitter_misc":{"Written by":"Simon Taranto","Est. reading time":"4 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.backerkit.com\/blog\/using-rails-messageverifier-for-stateless-token-management\/#article","isPartOf":{"@id":"https:\/\/www.backerkit.com\/blog\/using-rails-messageverifier-for-stateless-token-management\/"},"author":{"name":"Simon Taranto","@id":"https:\/\/www.backerkit.com\/blog\/#\/schema\/person\/860d1b2b8b38a20bce936391e5ed85de"},"headline":"Using Rails&#8217; MessageVerifier for Stateless Token Management","datePublished":"2017-09-18T16:45:58+00:00","dateModified":"2020-02-21T08:40:42+00:00","mainEntityOfPage":{"@id":"https:\/\/www.backerkit.com\/blog\/using-rails-messageverifier-for-stateless-token-management\/"},"wordCount":511,"publisher":{"@id":"https:\/\/www.backerkit.com\/blog\/#organization"},"image":{"@id":"https:\/\/www.backerkit.com\/blog\/using-rails-messageverifier-for-stateless-token-management\/#primaryimage"},"thumbnailUrl":"https:\/\/www.backerkit.com\/blog\/wp-content\/uploads\/2017\/09\/Using-Rails-MessageVerifier-for-Stateless-Token-Management.png","articleSection":["Engineering"],"inLanguage":"en-US"},{"@type":"WebPage","@id":"https:\/\/www.backerkit.com\/blog\/using-rails-messageverifier-for-stateless-token-management\/","url":"https:\/\/www.backerkit.com\/blog\/using-rails-messageverifier-for-stateless-token-management\/","name":"Using Rails' MessageVerifier for Stateless Token Management | BackerKit","isPartOf":{"@id":"https:\/\/www.backerkit.com\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.backerkit.com\/blog\/using-rails-messageverifier-for-stateless-token-management\/#primaryimage"},"image":{"@id":"https:\/\/www.backerkit.com\/blog\/using-rails-messageverifier-for-stateless-token-management\/#primaryimage"},"thumbnailUrl":"https:\/\/www.backerkit.com\/blog\/wp-content\/uploads\/2017\/09\/Using-Rails-MessageVerifier-for-Stateless-Token-Management.png","datePublished":"2017-09-18T16:45:58+00:00","dateModified":"2020-02-21T08:40:42+00:00","breadcrumb":{"@id":"https:\/\/www.backerkit.com\/blog\/using-rails-messageverifier-for-stateless-token-management\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.backerkit.com\/blog\/using-rails-messageverifier-for-stateless-token-management\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.backerkit.com\/blog\/using-rails-messageverifier-for-stateless-token-management\/#primaryimage","url":"https:\/\/www.backerkit.com\/blog\/wp-content\/uploads\/2017\/09\/Using-Rails-MessageVerifier-for-Stateless-Token-Management.png","contentUrl":"https:\/\/www.backerkit.com\/blog\/wp-content\/uploads\/2017\/09\/Using-Rails-MessageVerifier-for-Stateless-Token-Management.png","width":1558,"height":748},{"@type":"BreadcrumbList","@id":"https:\/\/www.backerkit.com\/blog\/using-rails-messageverifier-for-stateless-token-management\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.backerkit.com\/blog\/"},{"@type":"ListItem","position":2,"name":"Using Rails&#8217; MessageVerifier for Stateless Token Management"}]},{"@type":"WebSite","@id":"https:\/\/www.backerkit.com\/blog\/#website","url":"https:\/\/www.backerkit.com\/blog\/","name":"Crowdfunding Blog &amp; Resources | BackerKit","description":"The BackerKit crowdfunding blog provides expert advice and success stories to help you plan, manage, and deliver a successful crowdfunding campaign.","publisher":{"@id":"https:\/\/www.backerkit.com\/blog\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.backerkit.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/www.backerkit.com\/blog\/#organization","name":"BackerKit","url":"https:\/\/www.backerkit.com\/blog\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.backerkit.com\/blog\/#\/schema\/logo\/image\/","url":"https:\/\/www.backerkit.com\/blog\/wp-content\/uploads\/2017\/02\/BackerKit-logo.png","contentUrl":"https:\/\/www.backerkit.com\/blog\/wp-content\/uploads\/2017\/02\/BackerKit-logo.png","width":1200,"height":345,"caption":"BackerKit"},"image":{"@id":"https:\/\/www.backerkit.com\/blog\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/www.facebook.com\/Backerkit\/","https:\/\/x.com\/backerkit","https:\/\/www.instagram.com\/backerkit\/","https:\/\/www.linkedin.com\/company\/backerkit","https:\/\/www.youtube.com\/channel\/UC3gch2VsESfv0XW36W7BBQg"]},{"@type":"Person","@id":"https:\/\/www.backerkit.com\/blog\/#\/schema\/person\/860d1b2b8b38a20bce936391e5ed85de","name":"Simon Taranto","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.backerkit.com\/blog\/#\/schema\/person\/image\/","url":"https:\/\/secure.gravatar.com\/avatar\/90212df57bf38f6f4e9cc846a23e49e9b9e19e8a5b8c32d5d01ec4d2fbd8b227?s=96&d=monsterid&r=pg","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/90212df57bf38f6f4e9cc846a23e49e9b9e19e8a5b8c32d5d01ec4d2fbd8b227?s=96&d=monsterid&r=pg","caption":"Simon Taranto"},"sameAs":["http:\/\/www.backerkit.com","https:\/\/x.com\/simontaranto"],"url":"https:\/\/www.backerkit.com\/blog\/author\/simon\/"}]}},"_links":{"self":[{"href":"https:\/\/www.backerkit.com\/blog\/wp-json\/wp\/v2\/posts\/6953","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.backerkit.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.backerkit.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.backerkit.com\/blog\/wp-json\/wp\/v2\/users\/20"}],"replies":[{"embeddable":true,"href":"https:\/\/www.backerkit.com\/blog\/wp-json\/wp\/v2\/comments?post=6953"}],"version-history":[{"count":10,"href":"https:\/\/www.backerkit.com\/blog\/wp-json\/wp\/v2\/posts\/6953\/revisions"}],"predecessor-version":[{"id":7092,"href":"https:\/\/www.backerkit.com\/blog\/wp-json\/wp\/v2\/posts\/6953\/revisions\/7092"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.backerkit.com\/blog\/wp-json\/wp\/v2\/media\/7089"}],"wp:attachment":[{"href":"https:\/\/www.backerkit.com\/blog\/wp-json\/wp\/v2\/media?parent=6953"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.backerkit.com\/blog\/wp-json\/wp\/v2\/categories?post=6953"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.backerkit.com\/blog\/wp-json\/wp\/v2\/tags?post=6953"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}