public JObject Token(FormDataCollection request)
        {
            var client = AuthenticateClient(Request, request);

            AccessKey accessKey = null;
            var       grantType = GetRequiredParameter(request, "grant_type");

            switch (grantType)
            {
            case "authorization_code":
            {
                var code        = GetRequiredParameter(request, "code");
                var redirectUri = GetRequiredParameter(request, "redirect_uri");

                Guid authCode;
                if (!Guid.TryParse(code, out authCode))
                {
                    ThrowHttpResponse(HttpStatusCode.Forbidden, "Invalid authorization code!");
                }

                // find a valid grant by authorization code
                var grant = DataContext.OAuthGrant.Get(authCode);
                if (grant == null || grant.ClientID != client.ID || grant.Type != (int)OAuthGrantType.Code || grant.RedirectUri != redirectUri)
                {
                    ThrowHttpResponse(HttpStatusCode.Forbidden, "Invalid authorization code!");
                }

                if (DateTime.UtcNow > grant.Timestamp.AddMinutes(10))
                {
                    ThrowHttpResponse(HttpStatusCode.Forbidden, "Invalid authorization code!");
                }

                grant.AuthCode = null;         // deny subsequent requests with the same authorization code
                DataContext.OAuthGrant.Save(grant);

                accessKey = grant.AccessKey;
            }
            break;

            case "password":
            {
                var scope    = GetRequiredParameter(request, "scope");
                var username = GetRequiredParameter(request, "username");
                var password = GetRequiredParameter(request, "password");

                // authenticate user
                User user = null;
                try
                {
                    user = _authenticationManager.AuthenticateByPassword(username, password);
                }
                catch (AuthenticationException)
                {
                    ThrowHttpResponse(HttpStatusCode.Unauthorized, "Invalid credentials or account is disabled!");
                }

                // issue or renew grant
                var filter = new OAuthGrantFilter
                {
                    ClientID = client.ID,
                    Scope    = scope,
                    Type     = (int)OAuthGrantType.Password,
                };

                var grant = DataContext.OAuthGrant.GetByUser(user.ID, filter).FirstOrDefault() ??
                            new OAuthGrant(client, user.ID, new AccessKey(), (int)OAuthGrantType.Password, scope);
                RenewGrant(grant);

                DataContext.AccessKey.Save(grant.AccessKey);
                DataContext.OAuthGrant.Save(grant);
                accessKey = grant.AccessKey;
            }
            break;

            default:
                ThrowHttpResponse(HttpStatusCode.BadRequest, "Invalid grant_type parameter!");
                break;
            }

            return(new JObject(
                       new JProperty("access_token", accessKey.Key),
                       new JProperty("token_type", "Bearer"),
                       new JProperty("expires_in", accessKey.ExpirationDate == null ? null :
                                     (int?)(int)accessKey.ExpirationDate.Value.Subtract(DateTime.UtcNow).TotalSeconds)));
        }