title: Proper way to test authenticated methods (using bearer tokens) in C# (web api)
body: <p>I have a Web API with tons of methods that all require a bearer token to be present in order to be used. These methods all extract information from the bearer token.</p>
  
  <p>I want to test whether the API is properly populating the bearer token upon its generation. I'm using the Microsoft.Owin.Testing framework to write my tests. I have a test that looks like this:</p>
  
  <pre><code>[TestMethod]
  public async Task test_Login() 
  {
      using (var server = TestServer.Create&lt;Startup&gt;())
      {
          var req = server.CreateRequest("/authtoken");
          req.AddHeader("Content-Type", "application/x-www-form-urlencoded");
          req.And(x =&gt; x.Content = new StringContent("grant_type=password&amp;username=test&amp;password=1234", System.Text.Encoding.ASCII));
          var response = await req.GetAsync();
  
          // Did the request produce a 200 OK response?
          Assert.AreEqual(response.StatusCode, System.Net.HttpStatusCode.OK);
  
          // Retrieve the content of the response
          string responseBody = await response.Content.ReadAsStringAsync();
          // this uses a custom method for deserializing JSON to a dictionary of objects using JSON.NET
          Dictionary&lt;string, object&gt; responseData = deserializeToDictionary(responseBody); 
  
          // Did the response come with an access token?
          Assert.IsTrue(responseData.ContainsKey("access_token"));
  
      }
  }
  </code></pre>
  
  <p>So I'm able to retrieve the string that represents the token. But now I want to actually access that token's contents, and make sure that certain claims were provided.</p>
  
  <p>Code that I would use in an actual authenticated method to check the claims looks like this:</p>
  
  <pre><code>var identity = (ClaimsIdentity)User.Identity;
  IEnumerable&lt;Claim&gt; claims = identity.Claims;
  
  var claimTypes = from x in claims select x.Type;
  
  if (!claimTypes.Contains("customData"))
      throw new InvalidOperationException("Not authorized");
  </code></pre>
  
  <p>So what I want to be able to do is, within my test itself, provide the bearer token string and reeceive a User.Identity object or in some other way gain access to the claims that token contains. This is how I want to test whether my method is properly adding the necessary claims to the token.</p>
  
  <p>The "naive" approach could be to write a method in my API that simply returns all the claims in the bearer token it is given. But it feels like this should be unnecessary. ASP.NET is somehow decoding the given token to an object before my controller's method is called. I want to replicate the same action on my own, in my test code. </p>
  
  <p>Can this be done? If so, how?</p>
  
  <hr>
  
  <p>EDIT: My OWIN startup class instantiates an authentication token provider that I have coded which handles authentication and token generation. In my startup class I have this:</p>
  
  <pre><code>public void Configuration(IAppBuilder app)
  {
      // Setup configuration object
      HttpConfiguration config = new HttpConfiguration();
  
      // Web API configuration and services
      // Configure Web API to use only bearer token authentication.
      config.SuppressDefaultHostAuthentication();
      config.Filters.Add(new HostAuthenticationFilter(OAuthDefaults.AuthenticationType));
  
      // Web API routes
      config.MapHttpAttributeRoutes();
      config.Routes.MapHttpRoute(
          name: "DefaultApi",
          routeTemplate: "api/{controller}/{id}",
          defaults: new { id = RouteParameter.Optional }
      );
  
      // configure the OAUTH server
      OAuthAuthorizationServerOptions OAuthServerOptions = new OAuthAuthorizationServerOptions()
      {
          //AllowInsecureHttp = false,
          AllowInsecureHttp = true, // THIS HAS TO BE CHANGED BEFORE PUBLISHING!
  
          TokenEndpointPath = new PathString("/authtoken"),
          AccessTokenExpireTimeSpan = TimeSpan.FromDays(1),
          Provider = new API.Middleware.MyOAuthProvider()
      };
  
      // Now we setup the actual OWIN pipeline.
  
      // setup CORS support
      // in production we will only allow from the correct URLs.
      app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);
  
      // Token Generation
      app.UseOAuthAuthorizationServer(OAuthServerOptions);
      app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions());
  
      // insert actual web API and we're off!
      app.UseWebApi(config);
  }
  </code></pre>
  
  <p>Here is the relevant code from my OAuth provider:</p>
  
  <pre><code>public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
  {
  
      // Will be used near end of function
      bool isValidUser = false;
  
      // Simple sanity check: all usernames must begin with a lowercase character
      Match testCheck = Regex.Match(context.UserName, "^[a-z]{1}.+$");
      if (testCheck.Success==false)
      {
          context.SetError("invalid_grant", "Invalid credentials.");
          return;
      }
  
      string userExtraInfo;
      // Here we check the database for a valid user.
      // If the user is valid, isValidUser will be set to True.
      // Invalid authentications will return null from the method below.
      userExtraInfo = DBAccess.getUserInfo(context.UserName, context.Password);
      if (userExtraInfo != null) isValidUser = true;
  
      if (!isValidUser)
      {
          context.SetError("invalid_grant", "Invalid credentials.");
          return;
      }
  
      // The database validated the user. We will include the username in the token.
      string userName = context.UserName;
  
      // generate a claims object
      var identity = new ClaimsIdentity(context.Options.AuthenticationType);
  
      // add the username to the token
      identity.AddClaim(new Claim(ClaimTypes.Sid, userName));
  
      // add the custom data on the user to the token.
      identity.AddClaim(new Claim("customData", userExtraInfo));
  
      // store token expiry so the consumer can determine expiration time
      DateTime expiresAt = DateTime.Now.Add(context.Options.AccessTokenExpireTimeSpan);
      identity.AddClaim(new Claim("expiry", expiresAt.ToString()));
  
      // Validate the request and generate a token.
      context.Validated(identity);
  
  }
  </code></pre>
  
  <p>The unit test would want to ensure that the <code>customData</code> claim is in fact present in the authentication token. So thus my need for a way to evaluate the token provided to test which claims it contains.</p>
  
  <hr>
  
  <p>EDIT 2: I've spent some time looking over the Katana source code and searching out some other posts online, and it looks like it's important that I'm hosting this app on IIS, so I would be using SystemWeb. It looks like SystemWeb uses Machine Key encryption for the token. It also looks like the <code>AccessTokenFormat</code> parameter in the options is relevant here. </p>
  
  <p>So now what I'm wondering is if I can instantiate my own "decoder" based on this knowledge. Assuming I will only ever be hosting on IIS, can I instantiate a decoder that can then decode the token and convert it into a Claims object? </p>
  
  <p>The docs on this are kind of sparse and the code seems to throw you all over the place, a lot to try to keep straight in my head. </p>
  
  <hr>
  
  <p>EDIT 3: I found a project that contains what is supposed to be a bearer token deserializer. I adapted the code in its "API" library and have been trying to use it to decrypt the tokens generated by my API.</p>
  
  <p>I generated a <code>&lt;machineKey...&gt;</code> value using a PowerShell script from Microsoft and placed it both in the Web.config file of the API itself and the App.confg file in the test project. </p>
  
  <p>The tokens still fail to decrypt, however. I receive a Exception thrown: <code>System.Security.Cryptography.CryptographicException</code> with the message <code>"Error occurred during a cryptographic operation."</code> The following is the stacktrace of the error:</p>
  
  <pre><code>at System.Web.Security.Cryptography.HomogenizingCryptoServiceWrapper.HomogenizeErrors(Func`2 func, Byte[] input)
  at System.Web.Security.Cryptography.HomogenizingCryptoServiceWrapper.Unprotect(Byte[] protectedData)
  at System.Web.Security.MachineKey.Unprotect(ICryptoServiceProvider cryptoServiceProvider, Byte[] protectedData, String[] purposes)
  at System.Web.Security.MachineKey.Unprotect(Byte[] protectedData, String[] purposes)
  at MyAPI.Tests.BearerTokenAPI.MachineKeyDataProtector.Unprotect(Byte[] protectedData) in D:\Source\MyAPI\MyAPI.WebAPI.Tests\BearerTokenAPI.cs:line 251
  at MyAPI.Tests.BearerTokenAPI.SecureDataFormat`1.Unprotect(String protectedText) in D:\Source\MyAPI\MyAPI.WebAPI.Tests\BearerTokenAPI.cs:line 287
  </code></pre>
  
  <p>At this point I'm stumped. With the MachineKey value set to the same across the entire project, I don't see why I'm unable to decrypt the tokens. I'm guessing the cryptographic error is being deliberately vague, but I am not sure where to start with figuring this out now. </p>
  
  <p>And all I wanted to do was test that the token contains the desired data in a unit test.... :-)</p>