title: 302 redirect after CORS preflight
body: <p>I'm running into a problem with a 302 redirect after my CORS preflight has successfully returned a 200 status. I'm currently building an app using Laravel 4.1 and Angular 1.2 as well as my own OAUTH2 server. </p>
  
  <p>The error that Chrome/FF/Safari are sending back to me is:</p>
  
  <blockquote>
    <p>XMLHttpRequest cannot load <code>http://localhost.api/api/v1/tracks?$filter=id%20eq%20guid%27d7de10ba-e353-455b-a3cb-ced9b4965141%27&amp;</code>. The request was redirected to '<code>http://localhost.api/session/invalid</code>', which is disallowed for cross-origin requests that require preflight.</p>
  </blockquote>
  
  <p>I assume whats causing my issue is the "redirect" thats happening - as my normal CORS requests all work as expected.</p>
  
  <p>My configuration for my Access-Control-Allow-* headers is fairly open right now during testing.  </p>
  
  <pre><code>  'paths' =&gt; array(
        '^/api/' =&gt; array(
            'allow_origin'=&gt; array('*'),
            'allow_headers'=&gt; array('Content-Type', 'Authorization'),
            'allow_methods'=&gt; array('POST', 'PUT', 'GET', 'DELETE', 'OPTIONS'),
            'max_age' =&gt; 0     
        ),                
        '^/session/' =&gt; array(
            'allow_origin'=&gt; array('*'),
            'allow_headers'=&gt; array('Content-Type', 'Authorization'),
            'allow_methods'=&gt; array('GET', 'OPTIONS'),               
            'max_age' =&gt; 0                                                        
        ) 
  </code></pre>
  
  <p>The redirect in question is in a pre-filter thats checking the validity of an OAUTH2 access token</p>
  
  <pre><code>public function filter($route, $request, $data = null)                       
  {                                                                            
      //  Get the authorization header or fail                                 
      if ($authorization = Request::header('Authorization', false)) {          
          list($type, $token) = explode(' ', $authorization);                  
          if (is_null($auth = OAuth2::token($token)-&gt;first())) {               
              return Redirect::to('session/invalid');                                                              
          }                                                                    
          $tokenExpiryDate = Carbon::createFromTimeStamp($auth-&gt;access_token_expires);
  
          //  If we don't have a Bearer authentication header                  
          //  or if the token has expired.  Then redirect to an                
          //  expired session route                                            
          if (   'bearer' != strtolower($type)                                 
              || Carbon::now()-&gt;gt($tokenExpiryDate)                           
          ) {                                                                  
              return Redirect::route(                                          
                  'expiredSession',                                            
                  array('expiry' =&gt; $tokenExpiryDate-&gt;timestamp)               
              );                                                               
          }                                                                    
      } else {                                                                 
          //  The authentication header is invalid, redirect to let the user know.
          return Redirect::to('session/invalid');                              
      }                                                                        
  }  
  </code></pre>
  
  <p>All these requests worked when I tried debugging using POSTMAN, but after my research I've basically found that extensions don't necessarily have to play by the same rules.  As well as I noticed my requests using POSTMAN never send any preflight OPTIONS requests when I initiate a simple GET, POST, etc..</p>
  
  <p>Here are the headers of both an OPTIONS request as well as a GET request to follow it that is returning my error</p>
  
  <h2>OPTIONS Request</h2>
  
  <pre><code>Remote Address:127.0.0.1:80 
  Request URL:http://localhost.api/api/v1/tracks?$filter=id%20eq%20guid%27d7de10ba-e353-455b-a3cb-ced9b4965141%27&amp;
  Request Method:OPTIONS
  Status Code:200 OK
  </code></pre>
  
  <p><strong>Request Headers</strong></p>
  
  <pre><code>Accept:*/*
  Accept-Encoding:gzip,deflate,sdch
  Accept-Language:en-US,en;q=0.8
  Access-Control-Request-Headers:accept, authorization
  Access-Control-Request-Method:GET
  Cache-Control:no-cache
  Connection:keep-alive
  DNT:1
  Host:vegas.ine.com
  Origin:http://localhost.angular
  Pragma:no-cache
  Referer:http://localhost.angular/admin/
  User-Agent:Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/34.0.1847.131 Safari/537.36   
  </code></pre>
  
  <p><strong>Response Headers</strong></p>
  
  <pre><code>Access-Control-Allow-Headers:content-type, authorization
  Access-Control-Allow-Methods:POST, PUT, GET, DELETE, OPTIONS
  Access-Control-Allow-Origin:http://localhost.angular
  Cache-Control:no-cache
  Connection:close
  Content-Type:text/html
  Date:Thu, 01 May 2014 16:22:19 GMT
  Server:Apache/2.2.26 (Unix) DAV/2 PHP/5.4.24 mod_ssl/2.2.26 OpenSSL/0.9.8y
  Set-Cookie:laravel_session=eyJpdiI6IktOZjlTM1ZVNUx0TEhoaTczY3dQcDBKRWlvbnppbDA3QTdqSENJdTc2R1U9IiwidmFsdWUiOiJEZ2ltXC9mNm1Qa20rV3BVRlNHTXgySGtUeVlpNjNZcGFudDFBWDJJekl1MEVNVlhSRE5WWk5YZDNxUkZuU0VEVytcL3NLNlVBXC9hZWtJQzdHU2FqVWtMdz09IiwibWFjIjoiYTYxYjEwNjlmYmI2MjMwNmE4MzlkYjIwNGZlNzA4Y2ViZGVkZmU1MTQzMzc5NmU2YzI2ZGExNzYxY2U5ZjdiMCJ9; expires=Thu, 01-May-2014 18:22:19 GMT; path=/; httponly
  X-Frame-Options:SAMEORIGIN
  X-Powered-By:PHP/5.4.24  
  </code></pre>
  
  <h2>GET Request</h2>
  
  <pre><code>Remote Address:127.0.0.1:80
  Request URL:http://localhost.api/api/v1/tracks?$filter=id%20eq%20guid%27d7de10ba-e353-455b-a3cb-ced9b4965141%27&amp;
  Request Method:GET
  Status Code:302 Found
  </code></pre>
  
  <p><strong>Request Headers</strong></p>
  
  <pre><code>Accept:application/json, text/plain, */*
  Accept-Encoding:gzip,deflate,sdch
  Accept-Language:en-US,en;q=0.8
  Authorization:Bearer 6Ss4XPrPM5jQD7Es0dz7TPRQ76hGA69vT9K94pst
  Cache-Control:no-cache
  Connection:keep-alive
  DNT:1
  Host:vegas.ine.com
  Origin:http://localhost.angular
  Pragma:no-cache
  Referer:http://localhost.angular/admin/
  User-Agent:Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/34.0.1847.131 Safari/537.36
  </code></pre>
  
  <p><strong>Response Headers</strong></p>
  
  <pre><code>Access-Control-Allow-Origin:http://localhost.angular
  Cache-Control:no-cache
  Connection:Keep-Alive
  Content-Type:text/html; charset=UTF-8
  Date:Thu, 01 May 2014 16:22:19 GMT
  Keep-Alive:timeout=5, max=100
  Location:http://localhost.api/session/invalid
  Server:Apache/2.2.26 (Unix) DAV/2 PHP/5.4.24 mod_ssl/2.2.26 OpenSSL/0.9.8y
  Set-Cookie:laravel_session=eyJpdiI6InlnREVPcUJTcyswMnRLanFDSlZ6QWFBVXZWMGdMNVNLYWxNTHRJVUlkalk9IiwidmFsdWUiOiJ4aXN5U0dcL1NYeGQrcUVzWFhYV3o2MWhcL25hQTlhcVUxbWxkN2R6SG9KZDNKaGNLTkRQY2FyTitpVHNGZzYxVVRtZUhoZGZRWE9GWjZRaDd1VVwvZUZuUT09IiwibWFjIjoiY2EzZTViZGIzZmVlMDcwZjdhMzBjOWQxYTgwZWNlYTJiMDk3ODdlZTk3NTYxMDNmM2YyODJjOGIxMzBmMmJlMiJ9; expires=Thu, 01-May-2014 18:22:20 GMT; path=/; httponly
  Transfer-Encoding:chunked
  Vary:Authorization
  X-Clockwork-Id:1398961340.2239.1349476325
  X-Clockwork-Version:1.5
  X-Frame-Options:SAMEORIGIN
  X-Powered-By:PHP/5.4.24
  </code></pre>