public void Authorize(HttpContext context, IDictionary <string, string> query)
        {
            string username       = "";
            string password       = "";
            string clientId       = "";
            string clientSecret   = "";
            string requestedScope = "";

            //expected but already parsed input is: grant_type
            //expected input is: username, password
            //optional input is: scope

            //load username
            if (query.ContainsKey("username"))
            {
                username = query["username"];
            }
            else
            {
                InvalidAuthorizationResponse errorResponse = new InvalidAuthorizationResponse();
                errorResponse.Error             = InvalidAuthorizationResponse.INVALID_REQUEST;
                errorResponse.Error_description = "The username is missing. The request must include the query parameter 'username'";
                //TODO: add URI
                context.Response.Payload.Write(JsonSerializer.SerializeJson(errorResponse));
                context.Response.Headers.Set("Content-Type", MimeType.APPLICATION_JSON);
                context.Response.Status = HttpStatus.BadRequest;
                return;
            }

            //load password
            if (query.ContainsKey("password"))
            {
                password = query["password"];
            }
            else
            {
                InvalidAuthorizationResponse errorResponse = new InvalidAuthorizationResponse();
                errorResponse.Error             = InvalidAuthorizationResponse.INVALID_REQUEST;
                errorResponse.Error_description = "The password is missing. The request must include the query parameter 'password'";
                //TODO: add URI
                context.Response.Payload.Write(JsonSerializer.SerializeJson(errorResponse));
                context.Response.Headers.Set("Content-Type", MimeType.APPLICATION_JSON);
                context.Response.Status = HttpStatus.BadRequest;
                return;
            }

            //load client ID:
            if (query.ContainsKey("client_id"))
            {
                clientId = query["client_id"];
            }
            else
            {
                InvalidAuthorizationResponse errorResponse = new InvalidAuthorizationResponse();
                errorResponse.Error             = InvalidAuthorizationResponse.INVALID_REQUEST;
                errorResponse.Error_description = "The client ID is missing. The request must include the query parameter 'client_id'";
                //TODO: add URI
                context.Response.Payload.Write(JsonSerializer.SerializeJson(errorResponse));
                context.Response.Headers.Set("Content-Type", MimeType.APPLICATION_JSON);
                context.Response.Status = HttpStatus.BadRequest;
                return;
            }

            //load client secret
            if (query.ContainsKey("client_secret"))
            {
                clientSecret = query["client_secret"];
            }

            //load scope
            if (query.ContainsKey("scope"))
            {
                requestedScope = query["scope"];
            }

            //step 1: check whether: 1) client exists, 2) client is not blocked, 3) client has user
            IClientAccount client = _clientStorage.GetClient(clientId);

            if (client == null || client.IsBlocked || !client.HasUser)
            {
                InvalidAuthorizationResponse errorResponse = new InvalidAuthorizationResponse();
                errorResponse.Error             = InvalidAuthorizationResponse.INVALID_CLIENT;
                errorResponse.Error_description = "The client ID is invalid";
                //TPDP: add URI
                context.Response.Payload.Write(JsonSerializer.SerializeJson(errorResponse));
                context.Response.Headers.Set("Content-Type", MimeType.APPLICATION_JSON);
                context.Response.Status = HttpStatus.Unauthorized;
                return;
            }

            //step 2 (if applicable): 1) check whether client's secret is set (if enabled) and 2) if it is correct
            if (client.IsClientSecretRequiredForPasswordGrant)
            {
                if (String.IsNullOrWhiteSpace(clientSecret))
                {
                    InvalidAuthorizationResponse errorResponse = new InvalidAuthorizationResponse();
                    errorResponse.Error             = InvalidAuthorizationResponse.INVALID_REQUEST;
                    errorResponse.Error_description = "The client secret is missing. The request must include the query parameter 'client_secret'";
                    //TODO: add URI
                    context.Response.Payload.Write(JsonSerializer.SerializeJson(errorResponse));
                    context.Response.Headers.Set("Content-Type", MimeType.APPLICATION_JSON);
                    context.Response.Status = HttpStatus.BadRequest;
                    return;
                }
                if (client.ClientSecret.CompareTo(clientSecret) != 0)
                {
                    InvalidAuthorizationResponse errorResponse = new InvalidAuthorizationResponse();
                    errorResponse.Error             = InvalidAuthorizationResponse.INVALID_CLIENT;
                    errorResponse.Error_description = "The client ID or secret is invalid";
                    //TODO: add URI
                    context.Response.Payload.Write(JsonSerializer.SerializeJson(errorResponse));
                    context.Response.Headers.Set("Content-Type", MimeType.APPLICATION_JSON);
                    context.Response.Status = HttpStatus.Unauthorized;
                    return;
                }
            }

            //step 3: check whether 1) user exists, 2) user is not blocked, 3) password is correct and 4) the user belongs to the passed client
            IUserAccount user = _userStorage.GetUserByName(username);

            if (user == null || user.IsBlocked || user.Password.CompareTo(password) != 0 || user.ClientId.CompareTo(clientId) != 0)
            {
                InvalidAuthorizationResponse errorResponse = new InvalidAuthorizationResponse();
                errorResponse.Error             = InvalidAuthorizationResponse.INVALID_CLIENT;
                errorResponse.Error_description = "The username or password invalid";
                //TODO: add URI
                context.Response.Payload.Write(JsonSerializer.SerializeJson(errorResponse));
                context.Response.Headers.Set("Content-Type", MimeType.APPLICATION_JSON);
                context.Response.Status = HttpStatus.Unauthorized;
                return;
            }

            //step 4: validate scope
            string finalScope = "";

            if (String.IsNullOrWhiteSpace(requestedScope))
            {
                finalScope = user.Scope;
            }
            else
            {
                //extract single scopes from requested scope
                string[] scopes;
                if (requestedScope.Contains(","))
                {
                    scopes = requestedScope.Split(',');
                }
                else if (requestedScope.Contains(";"))
                {
                    scopes = requestedScope.Split(';');
                }
                else if (requestedScope.Contains(" "))
                {
                    scopes = requestedScope.Split(' ');
                }
                else
                {
                    scopes = new string[] { requestedScope };
                }

                //check whether all requested scopes are permitted:
                IList <string> permittedScope = user.GetScopeAsList;
                foreach (string scope in scopes)
                {
                    if (!permittedScope.Contains(scope))
                    {
                        InvalidAuthorizationResponse errorResponse = new InvalidAuthorizationResponse();
                        errorResponse.Error             = InvalidAuthorizationResponse.INVALID_SCOPE;
                        errorResponse.Error_description = "The scope '" + scope + "' is not permitted or unknown";
                        //TODO: add URL
                        context.Response.Payload.Write(JsonSerializer.SerializeJson(errorResponse));
                        context.Response.Headers.Set("Content-Type", MimeType.APPLICATION_JSON);
                        context.Response.Status = HttpStatus.BadRequest;
                        return;
                    }
                    finalScope += scope + " ";
                }
                finalScope.Trim();
            }

            //step 6: create access token and (if applicable) refresh token
            AccessToken accessToken  = _reference.GenerateAccessToken(username, clientId, finalScope, client.AccessTokenExpiryInSeconds);
            string      refreshToken = _reference.GenerateRefreshToken(username, clientId, finalScope, client.RefreshTokenExpiryInSeconds);

            //step 7: return access token and (if applicable) refresh token
            accessToken.RefreshToken = refreshToken;
            context.Response.Payload.Write(JsonSerializer.SerializeJson(accessToken));
            context.Response.Headers.Set("Content-Type", MimeType.APPLICATION_JSON);
            context.Response.Headers.Set("Cache-Control", "no-store");
            context.Response.Headers.Set("Pragma", "no-cache");
            context.Response.Status = HttpStatus.OK;
        }
        public void Authorize(HttpContext context, IDictionary <string, string> query)
        {
            string clientId       = "";
            string clientSecret   = "";
            string requestedScope = "";

            //expected but already parsed input is: grant_type
            //expected input is: client_id, client_secret
            //optional input is: scope


            //load client ID
            if (query.ContainsKey("client_id"))
            {
                clientId = query["client_id"];
            }
            else
            {
                InvalidAuthorizationResponse errorResponse = new InvalidAuthorizationResponse();
                errorResponse.Error             = InvalidAuthorizationResponse.INVALID_REQUEST;
                errorResponse.Error_description = "The client ID is missing. The request must include the query parameter 'client_id'";
                //TODO: add URI
                context.Response.Payload.Write(JsonSerializer.SerializeJson(errorResponse));
                context.Response.Headers.Set("Content-Type", MimeType.APPLICATION_JSON);
                context.Response.Status = HttpStatus.BadRequest;
                return;
            }

            //load client secret
            if (query.ContainsKey("client_secret"))
            {
                clientSecret = query["client_secret"];
            }
            else
            {
                InvalidAuthorizationResponse errorResponse = new InvalidAuthorizationResponse();
                errorResponse.Error             = InvalidAuthorizationResponse.INVALID_REQUEST;
                errorResponse.Error_description = "The client secret is missing. The request must include the query parameter 'client_secret'";
                //TODO: add URI
                context.Response.Payload.Write(JsonSerializer.SerializeJson(errorResponse));
                context.Response.Headers.Set("Content-Type", MimeType.APPLICATION_JSON);
                context.Response.Status = HttpStatus.BadRequest;
                return;
            }

            //load scope
            if (query.ContainsKey("scope"))
            {
                requestedScope = query["scope"];
            }

            //step 1: check whether: 1) client exists, 2) client is not blocked, 3) credentials are correct
            IClientAccount client = _storage.GetClient(clientId);

            if (client == null || client.IsBlocked || client.ClientSecret.CompareTo(clientSecret) != 0)
            {
                InvalidAuthorizationResponse errorResponse = new InvalidAuthorizationResponse();
                errorResponse.Error             = InvalidAuthorizationResponse.INVALID_CLIENT;
                errorResponse.Error_description = "The client ID or secret is invalid";
                //TPDP: add URI
                context.Response.Payload.Write(JsonSerializer.SerializeJson(errorResponse));
                context.Response.Headers.Set("Content-Type", MimeType.APPLICATION_JSON);
                context.Response.Status = HttpStatus.Unauthorized;
                return;
            }

            //step 2: validate scope
            string finalScope = "";

            if (String.IsNullOrWhiteSpace(requestedScope))
            {
                finalScope = client.Scope;
            }
            else
            {
                //extract single scopes from requested scope
                string[] scopes;
                if (requestedScope.Contains(","))
                {
                    scopes = requestedScope.Split(',');
                }
                else if (requestedScope.Contains(";"))
                {
                    scopes = requestedScope.Split(';');
                }
                else if (requestedScope.Contains(" "))
                {
                    scopes = requestedScope.Split(' ');
                }
                else
                {
                    scopes = new string[] { requestedScope };
                }

                //check whether all requested scopes are permitted:
                IList <string> permittedScope = client.GetScopeAsList;
                foreach (string scope in scopes)
                {
                    if (!permittedScope.Contains(scope))
                    {
                        InvalidAuthorizationResponse errorResponse = new InvalidAuthorizationResponse();
                        errorResponse.Error             = InvalidAuthorizationResponse.INVALID_SCOPE;
                        errorResponse.Error_description = "The scope '" + scope + "' is not permitted or unknown";
                        //TODO: add URL
                        context.Response.Payload.Write(JsonSerializer.SerializeJson(errorResponse));
                        context.Response.Headers.Set("Content-Type", MimeType.APPLICATION_JSON);
                        context.Response.Status = HttpStatus.BadRequest;
                        return;
                    }
                    finalScope += scope + " ";
                }
                finalScope.Trim();
            }

            //step 3: create access token and (if applicable) refresh token
            AccessToken accessToken  = _reference.GenerateAccessToken(null, clientId, finalScope, client.AccessTokenExpiryInSeconds);
            string      refreshToken = _reference.GenerateRefreshToken(null, clientId, finalScope, client.RefreshTokenExpiryInSeconds);

            //step 4: return access token and (if applicable) refresh token
            accessToken.RefreshToken = refreshToken;
            context.Response.Payload.Write(JsonSerializer.SerializeJson(accessToken));
            context.Response.Headers.Set("Content-Type", MimeType.APPLICATION_JSON);
            context.Response.Headers.Set("Cache-Control", "no-store");
            context.Response.Headers.Set("Pragma", "no-cache");
            context.Response.Status = HttpStatus.OK;
        }
예제 #3
0
        public void Authorize(HttpContext context, IDictionary <string, string> query)
        {
            string refreshToken;
            string clientId       = "";
            string clientSecret   = "";
            string username       = "";
            string userPassword   = "";
            string requestedScope = "";

            //expected but already parsed input is: grant_type
            //expected input is: refresh token
            //expected input is (if enabled): client ID
            //expected input is (if enabled): client secret
            //expected input is (if enabled): user ID
            //expected input is (if enabled): user password
            //optional input is: scope

            //load refresh token
            if (query.ContainsKey("refresh_token"))
            {
                refreshToken = query["refresh_token"];
            }
            else
            {
                InvalidAuthorizationResponse errorResponse = new InvalidAuthorizationResponse();
                errorResponse.Error             = InvalidAuthorizationResponse.INVALID_REQUEST;
                errorResponse.Error_description = "The refresh token is missing. The request must include the query parameter 'refresh_token'";
                //TODO: add URI
                context.Response.Payload.Write(JsonSerializer.SerializeJson(errorResponse));
                context.Response.Headers.Set("Content-Type", MimeType.APPLICATION_JSON);
                context.Response.Status = HttpStatus.BadRequest;
                return;
            }

            //load client ID
            if (query.ContainsKey("client_id"))
            {
                clientId = query["client_id"];
            }

            //load client secret
            if (query.ContainsKey("client_secret"))
            {
                clientSecret = query["client_secret"];
            }

            //load user ID
            if (query.ContainsKey("username"))
            {
                username = query["username"];
            }

            //load user password
            if (query.ContainsKey("password"))
            {
                userPassword = query["password"];
            }

            //load scope
            if (query.ContainsKey("scope"))
            {
                requestedScope = query["scope"];
            }

            //step 1: load refresh token and check whether the refresh token is listed and is valid
            IRefreshToken refreshTokenSet = _refreshStorage.GetRefreshToken(refreshToken);

            if (refreshTokenSet == null || refreshTokenSet.IsInvalidated)
            {
                InvalidAuthorizationResponse errorResponse = new InvalidAuthorizationResponse();
                errorResponse.Error             = InvalidAuthorizationResponse.INVALID_CLIENT;
                errorResponse.Error_description = "The refresh token is invalid";
                //TODO: add uri
                context.Response.Payload.Write(JsonSerializer.SerializeJson(errorResponse));
                context.Response.Headers.Set("Content-Type", MimeType.APPLICATION_JSON);
                context.Response.Status = HttpStatus.Unauthorized;
                return;
            }
            //step 2: check whether the refresh token has expired
            if (refreshTokenSet.ValidUntil > 0 && refreshTokenSet.ValidUntil < DateTimeOffset.UtcNow.ToUnixTimeSeconds())
            {
                InvalidAuthorizationResponse errorResponse = new InvalidAuthorizationResponse();
                errorResponse.Error             = InvalidAuthorizationResponse.INVALID_CLIENT;
                errorResponse.Error_description = "The refresh token has expired";
                //TODO: add uri
                context.Response.Payload.Write(JsonSerializer.SerializeJson(errorResponse));
                context.Response.Headers.Set("Content-Type", MimeType.APPLICATION_JSON);
                context.Response.Status = HttpStatus.Unauthorized;
                return;
            }

            //step 3: load client and check whether the client is blocked
            IClientAccount client = _clientStorage.GetClient(refreshTokenSet.ClientId);

            if (client == null || client.IsBlocked)
            {
                InvalidAuthorizationResponse errorResponse = new InvalidAuthorizationResponse();
                errorResponse.Error             = InvalidAuthorizationResponse.INVALID_CLIENT;
                errorResponse.Error_description = "The refresh token has been issued to a client which is not existing or has been blocked";
                //TODO: add URI
                context.Response.Payload.Write(JsonSerializer.SerializeJson(errorResponse));
                context.Response.Headers.Set("Content-Type", MimeType.APPLICATION_JSON);
                context.Response.Status = HttpStatus.Unauthorized;
                return;
            }

            //step 3a (if enabled): check whether client is linked to the refresh token
            if (client.IsClientIdRequiredForRefreshToken)
            {
                if (String.IsNullOrWhiteSpace(clientId))
                {
                    InvalidAuthorizationResponse errorResponse = new InvalidAuthorizationResponse();
                    errorResponse.Error             = InvalidAuthorizationResponse.INVALID_REQUEST;
                    errorResponse.Error_description = "The client ID is missing. The request must include the query parameter 'client_id'";
                    //TODO: add URI
                    context.Response.Payload.Write(JsonSerializer.SerializeJson(errorResponse));
                    context.Response.Headers.Set("Content-Type", MimeType.APPLICATION_JSON);
                    context.Response.Status = HttpStatus.BadRequest;
                    return;
                }
                if (client.ClientId.CompareTo(clientId) != 0)
                {
                    InvalidAuthorizationResponse errorResponse = new InvalidAuthorizationResponse();
                    errorResponse.Error             = InvalidAuthorizationResponse.INVALID_CLIENT;
                    errorResponse.Error_description = "The client ID is invalid";
                    //TODO: add URI
                    context.Response.Payload.Write(JsonSerializer.SerializeJson(errorResponse));
                    context.Response.Headers.Set("Content-Type", MimeType.APPLICATION_JSON);
                    context.Response.Status = HttpStatus.Unauthorized;
                    return;
                }
            }

            //step 3b (if enabled): check whether client secret is valid
            if (client.IsClientSecretRequiredForRefreshToken)
            {
                if (String.IsNullOrWhiteSpace(clientSecret))
                {
                    InvalidAuthorizationResponse errorResponse = new InvalidAuthorizationResponse();
                    errorResponse.Error             = InvalidAuthorizationResponse.INVALID_REQUEST;
                    errorResponse.Error_description = "The client secret is missing. The request must include the query parameter 'client_secret'";
                    //TODO: add URI
                    context.Response.Payload.Write(JsonSerializer.SerializeJson(errorResponse));
                    context.Response.Headers.Set("Content-Type", MimeType.APPLICATION_JSON);
                    context.Response.Status = HttpStatus.BadRequest;
                    return;
                }
                if (client.ClientSecret.CompareTo(clientSecret) != 0)
                {
                    InvalidAuthorizationResponse errorResponse = new InvalidAuthorizationResponse();
                    errorResponse.Error             = InvalidAuthorizationResponse.INVALID_CLIENT;
                    errorResponse.Error_description = "The client ID or secret is invalid";
                    //TODO: add URI
                    context.Response.Payload.Write(JsonSerializer.SerializeJson(errorResponse));
                    context.Response.Headers.Set("Content-Type", MimeType.APPLICATION_JSON);
                    context.Response.Status = HttpStatus.Unauthorized;
                    return;
                }
            }

            IUserAccount user = null;

            if (client.HasUser)
            {
                //step 4a: check whether the refresh token has been issued to a user
                if (String.IsNullOrWhiteSpace(refreshTokenSet.Subject))
                {
                    InvalidAuthorizationResponse errorResponse = new InvalidAuthorizationResponse();
                    errorResponse.Error             = InvalidAuthorizationResponse.INVALID_CLIENT;
                    errorResponse.Error_description = "The refresh token is invalid";
                    //TODO: add uri
                    context.Response.Payload.Write(JsonSerializer.SerializeJson(errorResponse));
                    context.Response.Headers.Set("Content-Type", MimeType.APPLICATION_JSON);
                    context.Response.Status = HttpStatus.Unauthorized;
                    return;
                }

                user = _userStorage.GetUserByName(refreshTokenSet.Subject);
                //step 4b: check whether the user is existing and not blocked
                if (user == null || user.IsBlocked)
                {
                    InvalidAuthorizationResponse errorResponse = new InvalidAuthorizationResponse();
                    errorResponse.Error             = InvalidAuthorizationResponse.INVALID_CLIENT;
                    errorResponse.Error_description = "The refresh token has been issued to a user which is not existing or has been blocked";
                    //TODO: add URI
                    context.Response.Payload.Write(JsonSerializer.SerializeJson(errorResponse));
                    context.Response.Headers.Set("Content-Type", MimeType.APPLICATION_JSON);
                    context.Response.Status = HttpStatus.Unauthorized;
                    return;
                }

                //step 4c: check whether the linked subject (user ID) matches the passed user ID (if enabled)
                if (client.IsUserIdRequiredForRefreshToken)
                {
                    if (String.IsNullOrWhiteSpace(username))
                    {
                        InvalidAuthorizationResponse errorResponse = new InvalidAuthorizationResponse();
                        errorResponse.Error             = InvalidAuthorizationResponse.INVALID_REQUEST;
                        errorResponse.Error_description = "The username is missing. The request must include the query parameter 'username'";
                        //TODO: add URI
                        context.Response.Payload.Write(JsonSerializer.SerializeJson(errorResponse));
                        context.Response.Headers.Set("Content-Type", MimeType.APPLICATION_JSON);
                        context.Response.Status = HttpStatus.BadRequest;
                        return;
                    }

                    if (refreshTokenSet.Subject.CompareTo(username) != 0)
                    {
                        InvalidAuthorizationResponse errorResponse = new InvalidAuthorizationResponse();
                        errorResponse.Error             = InvalidAuthorizationResponse.INVALID_CLIENT;
                        errorResponse.Error_description = "The username is invalid";
                        //TODO: add URI
                        context.Response.Payload.Write(JsonSerializer.SerializeJson(errorResponse));
                        context.Response.Headers.Set("Content-Type", MimeType.APPLICATION_JSON);
                        context.Response.Status = HttpStatus.Unauthorized;
                        return;
                    }
                }

                //step 4d: check whether the passed user password is correct (if enabled)
                if (client.IsUserPasswordRequiredForRefreshToken)
                {
                    if (String.IsNullOrWhiteSpace(userPassword))
                    {
                        InvalidAuthorizationResponse errorResponse = new InvalidAuthorizationResponse();
                        errorResponse.Error             = InvalidAuthorizationResponse.INVALID_REQUEST;
                        errorResponse.Error_description = "The password is missing. The request must include the query parameter 'password'";
                        //TODO: add URI
                        context.Response.Payload.Write(JsonSerializer.SerializeJson(errorResponse));
                        context.Response.Headers.Set("Content-Type", MimeType.APPLICATION_JSON);
                        context.Response.Status = HttpStatus.BadRequest;
                        return;
                    }

                    if (user.Password.CompareTo(userPassword) != 0)
                    {
                        InvalidAuthorizationResponse errorResponse = new InvalidAuthorizationResponse();
                        errorResponse.Error             = InvalidAuthorizationResponse.INVALID_CLIENT;
                        errorResponse.Error_description = "The username or password is invalid";
                        //TODO: add URI
                        context.Response.Payload.Write(JsonSerializer.SerializeJson(errorResponse));
                        context.Response.Headers.Set("Content-Type", MimeType.APPLICATION_JSON);
                        context.Response.Status = HttpStatus.Unauthorized;
                        return;
                    }
                }
            }
            else
            {
                //check whether client has NO user, but the refresh token has been issued to a user:
                if (!String.IsNullOrWhiteSpace(refreshTokenSet.Subject))
                {
                    InvalidAuthorizationResponse errorResponse = new InvalidAuthorizationResponse();
                    errorResponse.Error             = InvalidAuthorizationResponse.INVALID_CLIENT;
                    errorResponse.Error_description = "The refresh token is invalid";
                    //TODO: add uri
                    context.Response.Payload.Write(JsonSerializer.SerializeJson(errorResponse));
                    context.Response.Headers.Set("Content-Type", MimeType.APPLICATION_JSON);
                    context.Response.Status = HttpStatus.Unauthorized;
                    return;
                }
            }

            //step 4: check scope
            string finalScope = "";

            if (String.IsNullOrWhiteSpace(requestedScope))
            {
                finalScope = refreshTokenSet.Scope;
            }
            else
            {
                //extract single scopes from requested scope
                string[] scopes;
                if (requestedScope.Contains(","))
                {
                    scopes = requestedScope.Split(',');
                }
                else if (requestedScope.Contains(";"))
                {
                    scopes = requestedScope.Split(';');
                }
                else if (requestedScope.Contains(" "))
                {
                    scopes = requestedScope.Split(' ');
                }
                else
                {
                    scopes = new string[] { requestedScope };
                }

                //check whether all requested scopes are permitted:
                IList <string> permittedScope = refreshTokenSet.GetScopeAsList;
                foreach (string scope in scopes)
                {
                    if (!permittedScope.Contains(scope))
                    {
                        InvalidAuthorizationResponse errorResponse = new InvalidAuthorizationResponse();
                        errorResponse.Error             = InvalidAuthorizationResponse.INVALID_SCOPE;
                        errorResponse.Error_description = "The scope '" + scope + "' is not permitted or unknown";
                        //TODO: add URL
                        context.Response.Payload.Write(JsonSerializer.SerializeJson(errorResponse));
                        context.Response.Headers.Set("Content-Type", MimeType.APPLICATION_JSON);
                        context.Response.Status = HttpStatus.BadRequest;
                        return;
                    }
                    finalScope += scope + " ";
                }
                finalScope.Trim();
            }

            //step 5: create new access token and issue new refresh token (if enabled and applicable)
            string subject;

            if (user == null)
            {
                subject = null;
            }
            else
            {
                subject = user.Username;
            }

            AccessToken accessToken = _reference.GenerateAccessToken(subject, clientId, finalScope, client.AccessTokenExpiryInSeconds);

            if (_issuesNewRefreshToken && refreshTokenSet.ValidUntil - DateTimeOffset.UtcNow.ToUnixTimeSeconds() < _newRefreshTokenExpiryThreshold)
            {
                accessToken.RefreshToken = _reference.GenerateRefreshToken(subject, client.ClientId, finalScope, client.RefreshTokenExpiryInSeconds);
            }
            else
            {
                accessToken.RefreshToken = null;
            }
            context.Response.Payload.Write(JsonSerializer.SerializeJson(accessToken));
            context.Response.Headers.Set("Content-Type", MimeType.APPLICATION_JSON);
            context.Response.Headers.Set("Cache-Control", "no-store");
            context.Response.Headers.Set("Pragma", "no-cache");
            context.Response.Status = HttpStatus.OK;
        }