title: HapiJS Proxy Trouble
body: <h1>TL;DR</h1>
  <p>How do I intercept a request, ping a different route for an ID, store the ID in a session, then continue the original request (especially PUT/POST with payloads) using the ID I just got?</p>
  <h1>Background</h1>
  <p>I am using HapiJS (8) to proxy requests from the client to an existing API (where I have no control over processes/logic). The API requires each request to contain a 'session ID' in either the query string or the payload (depending on the http method). In order to get a session ID, all I have to do is ask for one... there is no username/pwd required (it uses Basic auth in the headers). The session ID expires every 24 hours if it isn't renewed. Each client has their own session ID.</p>
  <p>I am currently using <a href="https://www.npmjs.com/package/hapi-auth-cookie" rel="nofollow noreferrer">hapi-auth-cookie</a> to store the value of the session ID which gets queried when the ID is needed. If the ID is expired or null, I need to request a new one before the client's request can be successfully proxy'd to the API.</p>
  <h1>Current Solution</h1>
  <p>When the client's request method is 'GET', I am handling this challenge quite gracefully utilizing the <code>appendNext</code> configuration described in the <a href="https://github.com/hapijs/hapi-auth-cookie" rel="nofollow noreferrer">hapi-auth-cookie docs</a>. The request is intercepted by hapi-auth-cookie, if a new session ID is needed, a request is sent to that particular route to get it, the API returns the ID which is then assigned to the Hapi session, and then (using <a href="https://github.com/hapijs/wreck" rel="nofollow noreferrer">Wreck</a>) a <code>reply.redirect</code> returns to the original GET request where it completes. Seamless and graceful.</p>
  <p>However, I cannot figure out how to accomplish this same flow with different http methods that contain payloads of data.</p>
  <p>Is there something besides <code>reply.redirect</code> that will accomplish the same goal while maintaining original payloads and methods? Or is there a much better way to do this in general?</p>
  <h1>The Code (for what currently works for 'GET' requests)</h1>
  <p>main app file (hapi-auth-cookie configs)</p>
  <pre><code># register plugins
  server.register require('./plugins')
  , (err) -&gt;
      throw err if err
  
      # set authentication (NLS) configs
      server.auth.strategy 'session', 'cookie',
          password: 'session_pwd'
          cookie: 'ghsid'
          redirectTo: '/api/SessionID' #get new session ID
          isSecure: config.get 'ssl'
          appendNext: true
          ttl: config.get 'session_length'
  </code></pre>
  <p>Controller that leverages session authentication and invokes hapi-auth-cookie plugin:</p>
  <pre><code>simpleRequest:
      auth: 'session'
      handler: (request, reply) -&gt;
          qs = Qs.stringify request.query
          request.papi_url = &quot;/api/route/sample?#{qs}&quot;
  
          reply.proxy
              mapUri: (request, reply) -&gt;
                  auth = config.get 'basic_auth'
                  api_host = config.get 'api_host'
                  papi_url = request.papi_url
                  path = api_host + papi_url
                  next null, path, {authorization: auth}
  </code></pre>
  <p>Route for getting a new session ID</p>
  <pre><code>module.exports = [
  
      {
          path: '/api/SessionID'
          method: 'GET'
          config: SessionController.session
      }
  
  ]
  </code></pre>
  <p>Session Controller</p>
  <pre><code>Wreck       = require 'wreck'
  config      = require 'config'
  
  module.exports =
      session:
          description: 'Get new session ID'
  
          auth:
              mode: 'try'
              strategy: 'session'
  
          plugins:
              'hapi-auth-cookie':
                  redirectTo: false
  
          handler: (request, reply) -&gt;
  
              # request configs
              papi_url = &quot;/Session&quot;
              api_host = config.get 'api_host'
              url = api_host + papi_url
              opts =
                  headers:
                      'Authorization': config.get 'basic_auth'
                      'content-type': 'application/json;charset=UTF-8'
  
              # make request to PAPI
              Wreck.post url, opts, (err, res, body) -&gt;
                  throw new Error err if err
  
                  try
                      bdy = JSON.parse body
                      sess =
                          nls: bdy.SessionId
  
                      if bdy.SessionId
                          # authenticate user with NLS
                          request.auth.session.set sess
  
                          # redirect to initial route
                          reply.redirect request.url.query.next
  
                      else
                          return throw new Error
  
                  catch err
                      throw new Error err
  </code></pre>
  <h1>Final solution</h1>
  <p>Based on Matt Harrison's answer, I created a custom plugin that gets registered as an authentication scheme so I can control this per route.</p>
  <p>Here's the plugin code:</p>
  <pre><code>Wreck           = require 'wreck'
  config          = require 'config'
  
  exports.register = (server, options, next) -&gt;
      server.auth.scheme 'cookie', internals.implementation
      next()
  
  exports.register.attributes =
      name: 'Hapi Session Interceptor'
      version: '1.0.0'
  
  internals = {}
  
  internals.implementation = (server, options, next) -&gt;
  
      scheme = authenticate: (request, reply) -&gt;
  
          validate = -&gt;
  
              session = request.state.sessionID
              unless session
                  return unauthenticated()
  
              reply.continue(credentials: {'session': session})
  
          unauthenticated = -&gt;
  
              api_url = &quot;/SessionID&quot;
              api_host = config.get 'api_host'
              url = api_host + api_url
              opts =
                  headers:
                      'Authorization': config.get 'basic_auth'
                      'content-type': 'application/json;charset=UTF-8'
  
              # make request to API
              Wreck.post url, opts, (err, res, body) -&gt;
                  throw new Error err if err
  
                  bdy = JSON.parse body
                  sess =
                      session: bdy.SessionId
  
                  if bdy.SessionId
                      reply.state 'sessionID', bdy.SessionId
                      reply.continue(credentials: sess)
  
                  else
                      return throw new Error
  
          validate()
  
      return scheme
  </code></pre>