From 042709ad22de9e054671c15a5e1895a9d2292545 Mon Sep 17 00:00:00 2001 From: Umar Hussain Date: Sat, 12 Sep 2026 09:57:55 +0000 Subject: [PATCH 1/3] out_loki: add oauth2 support for loki output Signed-off-by: Umar Hussain --- plugins/out_loki/loki.c | 185 +++++++++++++++++- plugins/out_loki/loki.h | 6 + .../config/out_loki_oauth2_basic.yaml | 28 +++ .../out_loki_oauth2_private_key_jwt.yaml | 30 +++ .../out_loki/tests/test_out_loki_001.py | 95 ++++++++- 5 files changed, 341 insertions(+), 3 deletions(-) create mode 100644 tests/integration/scenarios/out_loki/config/out_loki_oauth2_basic.yaml create mode 100644 tests/integration/scenarios/out_loki/config/out_loki_oauth2_private_key_jwt.yaml diff --git a/plugins/out_loki/loki.c b/plugins/out_loki/loki.c index e09972d0d2a..c2adf44226b 100644 --- a/plugins/out_loki/loki.c +++ b/plugins/out_loki/loki.c @@ -29,7 +29,8 @@ #include #include #include - +#include +#include #include #include @@ -1084,6 +1085,10 @@ static void loki_config_destroy(struct flb_loki *ctx) flb_ra_destroy(ctx->ra_tenant_id_key); } + if (ctx->oauth2_ctx) { + flb_oauth2_destroy(ctx->oauth2_ctx); + } + if (ctx->remove_mpa) { flb_mp_accessor_destroy(ctx->remove_mpa); } @@ -1103,6 +1108,7 @@ static struct flb_loki *loki_config_create(struct flb_output_instance *ins, struct flb_upstream *upstream; char *compress; char *drop_single_key; + const char *tmp_str; /* Create context */ ctx = flb_calloc(1, sizeof(struct flb_loki)); @@ -1121,12 +1127,37 @@ static struct flb_loki *loki_config_create(struct flb_output_instance *ins, /* Set networking defaults */ flb_output_net_default(FLB_LOKI_HOST, FLB_LOKI_PORT, ins); + /* Initialize OAuth2 default config */ + ctx->oauth2_config.enabled = FLB_FALSE; + ctx->oauth2_config.auth_method = FLB_OAUTH2_AUTH_METHOD_BASIC; + ctx->oauth2_config.refresh_skew = FLB_OAUTH2_DEFAULT_SKEW_SECS; + ctx->oauth2_ctx = NULL; + ctx->oauth2_auth_method = NULL; + /* Load config map */ ret = flb_output_config_map_set(ins, (void *) ctx); if (ret == -1) { return NULL; } + /* Apply OAuth2 config map properties if any */ + if (ins->oauth2_config_map && mk_list_size(&ins->oauth2_properties) > 0) { + ret = flb_config_map_set(ins->config, + &ins->oauth2_properties, + ins->oauth2_config_map, + &ctx->oauth2_config); + if (ret == -1) { + flb_free(ctx); + return NULL; + } + + /* Handle oauth2.auth_method separately since it's stored in a different field */ + tmp_str = flb_kv_get_key_value("oauth2.auth_method", &ins->oauth2_properties); + if (tmp_str) { + ctx->oauth2_auth_method = tmp_str; + } + } + /* Initialize final remove_keys list */ flb_slist_create(&ctx->remove_keys_derived); @@ -1212,6 +1243,56 @@ static struct flb_loki *loki_config_create(struct flb_output_instance *ins, return NULL; } + if (ctx->oauth2_config.connect_timeout <= 0 && + ins->net_setup.connect_timeout > 0) { + ctx->oauth2_config.connect_timeout = ins->net_setup.connect_timeout; + } + + /* OAuth2 initialization */ + if (ctx->oauth2_config.enabled == FLB_TRUE) { + tmp_str = ctx->oauth2_auth_method ? ctx->oauth2_auth_method : + flb_output_get_property("oauth2.auth_method", ins); + + if (tmp_str == NULL || strcasecmp(tmp_str, "basic") == 0) { + ctx->oauth2_config.auth_method = FLB_OAUTH2_AUTH_METHOD_BASIC; + } + else if (strcasecmp(tmp_str, "post") == 0) { + ctx->oauth2_config.auth_method = FLB_OAUTH2_AUTH_METHOD_POST; + } + else if (strcasecmp(tmp_str, "private_key_jwt") == 0) { + ctx->oauth2_config.auth_method = + FLB_OAUTH2_AUTH_METHOD_PRIVATE_KEY_JWT; + } + else { + flb_plg_error(ctx->ins, "invalid oauth2.auth_method '%s'", tmp_str); + return NULL; + } + + if (!ctx->oauth2_config.token_url || !ctx->oauth2_config.client_id) { + flb_plg_error(ctx->ins, "oauth2 requires token_url and client_id"); + return NULL; + } + + if (ctx->oauth2_config.auth_method == FLB_OAUTH2_AUTH_METHOD_PRIVATE_KEY_JWT) { + if (!ctx->oauth2_config.jwt_key_file || + !ctx->oauth2_config.jwt_cert_file) { + flb_plg_error(ctx->ins, "oauth2 private_key_jwt requires " + "jwt_key_file and jwt_cert_file"); + return NULL; + } + } + else if (!ctx->oauth2_config.client_secret) { + flb_plg_error(ctx->ins, "oauth2 basic/post require client_secret"); + return NULL; + } + + ctx->oauth2_ctx = flb_oauth2_create_from_config(config, &ctx->oauth2_config); + if (!ctx->oauth2_ctx) { + flb_plg_error(ctx->ins, "failed to initialize oauth2 context"); + return NULL; + } + } + /* use TLS ? */ if (ins->use_tls == FLB_TRUE) { io_flags = FLB_IO_TLS; @@ -1995,11 +2076,24 @@ static int send_loki_payload(struct flb_loki *ctx, } /* Send HTTP request */ - ret = flb_http_do(c, &b_sent); + if (ctx->oauth2_ctx) { + ret = flb_http_do_with_oauth2(c, &b_sent, ctx->oauth2_ctx); + } + else { + ret = flb_http_do(c, &b_sent); + } payload_release(out_buf, compressed); /* Validate HTTP client return status */ if (ret == 0) { + /* OAuth2-authenticated 401s should be retried with a fresh token. */ + if (ctx->oauth2_ctx != NULL && c->resp.status == 401) { + flb_oauth2_invalidate_token(ctx->oauth2_ctx); + flb_http_client_destroy(c); + flb_upstream_conn_release(u_conn); + return FLB_RETRY; + } + /* * Only allow the following HTTP status: * @@ -2368,6 +2462,93 @@ static struct flb_config_map config_map[] = { "Set HTTP auth password" }, + /* OAuth2 client credentials */ + { + FLB_CONFIG_MAP_BOOL, "oauth2.enable", "false", + 0, FLB_TRUE, offsetof(struct flb_loki, oauth2_config.enabled), + "Enable OAuth2 client credentials for outgoing requests" + }, + { + FLB_CONFIG_MAP_STR, "oauth2.token_url", NULL, + 0, FLB_TRUE, offsetof(struct flb_loki, oauth2_config.token_url), + "OAuth2 token endpoint URL" + }, + { + FLB_CONFIG_MAP_STR, "oauth2.client_id", NULL, + 0, FLB_TRUE, offsetof(struct flb_loki, oauth2_config.client_id), + "OAuth2 client_id" + }, + { + FLB_CONFIG_MAP_STR, "oauth2.client_secret", NULL, + 0, FLB_TRUE, offsetof(struct flb_loki, oauth2_config.client_secret), + "OAuth2 client_secret" + }, + { + FLB_CONFIG_MAP_STR, "oauth2.user_agent", NULL, + 0, FLB_TRUE, offsetof(struct flb_loki, oauth2_config.user_agent), + "Optional User-Agent header for OAuth2 token requests" + }, + { + FLB_CONFIG_MAP_STR, "oauth2.scope", NULL, + 0, FLB_TRUE, offsetof(struct flb_loki, oauth2_config.scope), + "Optional OAuth2 scope" + }, + { + FLB_CONFIG_MAP_STR, "oauth2.audience", NULL, + 0, FLB_TRUE, offsetof(struct flb_loki, oauth2_config.audience), + "Optional OAuth2 audience parameter" + }, + { + FLB_CONFIG_MAP_STR, "oauth2.resource", NULL, + 0, FLB_TRUE, offsetof(struct flb_loki, oauth2_config.resource), + "Optional OAuth2 resource parameter" + }, + { + FLB_CONFIG_MAP_STR, "oauth2.auth_method", "basic", + 0, FLB_TRUE, offsetof(struct flb_loki, oauth2_auth_method), + "OAuth2 client authentication method: basic, post or private_key_jwt" + }, + { + FLB_CONFIG_MAP_STR, "oauth2.jwt_key_file", NULL, + 0, FLB_TRUE, offsetof(struct flb_loki, oauth2_config.jwt_key_file), + "Path to the private key file for private_key_jwt authentication" + }, + { + FLB_CONFIG_MAP_STR, "oauth2.jwt_cert_file", NULL, + 0, FLB_TRUE, offsetof(struct flb_loki, oauth2_config.jwt_cert_file), + "Path to the certificate file for private_key_jwt authentication" + }, + { + FLB_CONFIG_MAP_STR, "oauth2.jwt_aud", NULL, + 0, FLB_TRUE, offsetof(struct flb_loki, oauth2_config.jwt_aud), + "Audience for private_key_jwt assertion (defaults to oauth2.token_url)" + }, + { + FLB_CONFIG_MAP_STR, "oauth2.jwt_header", "kid", + 0, FLB_TRUE, offsetof(struct flb_loki, oauth2_config.jwt_header), + "Header field for private_key_jwt assertion" + }, + { + FLB_CONFIG_MAP_INT, "oauth2.jwt_ttl_seconds", "300", + 0, FLB_TRUE, offsetof(struct flb_loki, oauth2_config.jwt_ttl), + "TTL for private_key_jwt assertion" + }, + { + FLB_CONFIG_MAP_INT, "oauth2.refresh_skew_seconds", "60", + 0, FLB_TRUE, offsetof(struct flb_loki, oauth2_config.refresh_skew), + "Seconds before expiry to refresh the access token" + }, + { + FLB_CONFIG_MAP_TIME, "oauth2.timeout", "0s", + 0, FLB_TRUE, offsetof(struct flb_loki, oauth2_config.timeout), + "Timeout for OAuth2 token requests (defaults to response_timeout when unset)" + }, + { + FLB_CONFIG_MAP_TIME, "oauth2.connect_timeout", "0s", + 0, FLB_TRUE, offsetof(struct flb_loki, oauth2_config.connect_timeout), + "Connect timeout for OAuth2 token requests" + }, + { FLB_CONFIG_MAP_SIZE, "buffer_size", "512KB", 0, FLB_TRUE, offsetof(struct flb_loki, http_buffer_max_size), diff --git a/plugins/out_loki/loki.h b/plugins/out_loki/loki.h index e183114ec3d..e6857ad4cef 100644 --- a/plugins/out_loki/loki.h +++ b/plugins/out_loki/loki.h @@ -25,6 +25,7 @@ #include #include #include +#include #include #define FLB_LOKI_CT "Content-Type" @@ -80,6 +81,11 @@ struct flb_loki { /* Bearer Token Auth */ flb_sds_t bearer_token; + /* OAuth2 */ + struct flb_oauth2_config oauth2_config; + struct flb_oauth2 *oauth2_ctx; + const char *oauth2_auth_method; + /* Labels */ struct mk_list *labels; struct mk_list *label_keys; diff --git a/tests/integration/scenarios/out_loki/config/out_loki_oauth2_basic.yaml b/tests/integration/scenarios/out_loki/config/out_loki_oauth2_basic.yaml new file mode 100644 index 00000000000..037da5f9f23 --- /dev/null +++ b/tests/integration/scenarios/out_loki/config/out_loki_oauth2_basic.yaml @@ -0,0 +1,28 @@ +service: + flush: 1 + log_level: info + http_server: on + http_port: ${FLUENT_BIT_HTTP_MONITORING_PORT} + +pipeline: + inputs: + - name: dummy + samples: 1 + dummy: | + { + "message": "hello from out_loki oauth2 basic", + "source": "dummy" + } + + outputs: + - name: loki + match: "*" + host: 127.0.0.1 + port: ${TEST_SUITE_HTTP_PORT} + line_format: json + labels: job=integration-test + oauth2.enable: true + oauth2.token_url: http://127.0.0.1:${TEST_SUITE_HTTP_PORT}/oauth/token + oauth2.client_id: client1 + oauth2.client_secret: secret1 + oauth2.scope: logs.write diff --git a/tests/integration/scenarios/out_loki/config/out_loki_oauth2_private_key_jwt.yaml b/tests/integration/scenarios/out_loki/config/out_loki_oauth2_private_key_jwt.yaml new file mode 100644 index 00000000000..b846069db2e --- /dev/null +++ b/tests/integration/scenarios/out_loki/config/out_loki_oauth2_private_key_jwt.yaml @@ -0,0 +1,30 @@ +service: + flush: 1 + log_level: info + http_server: on + http_port: ${FLUENT_BIT_HTTP_MONITORING_PORT} + +pipeline: + inputs: + - name: dummy + samples: 1 + dummy: | + { + "message": "hello from out_loki oauth2 jwt", + "source": "dummy" + } + + outputs: + - name: loki + match: "*" + host: 127.0.0.1 + port: ${TEST_SUITE_HTTP_PORT} + line_format: json + labels: job=integration-test + oauth2.enable: true + oauth2.token_url: http://127.0.0.1:${TEST_SUITE_HTTP_PORT}/oauth/token + oauth2.client_id: client1 + oauth2.auth_method: private_key_jwt + oauth2.jwt_key_file: ${PRIVATE_KEY_TEST} + oauth2.jwt_cert_file: ${CERTIFICATE_TEST} + oauth2.jwt_aud: http://127.0.0.1:${TEST_SUITE_HTTP_PORT}/oauth/token diff --git a/tests/integration/scenarios/out_loki/tests/test_out_loki_001.py b/tests/integration/scenarios/out_loki/tests/test_out_loki_001.py index 63a52f0082b..fdc12b0caf0 100644 --- a/tests/integration/scenarios/out_loki/tests/test_out_loki_001.py +++ b/tests/integration/scenarios/out_loki/tests/test_out_loki_001.py @@ -3,9 +3,14 @@ from pathlib import Path import tempfile +import pytest import requests -from server.http_server import data_storage, http_server_run +from server.http_server import ( + configure_oauth_token_response, + data_storage, + http_server_run, +) from utils.memory_check import memory_check_enabled from utils.test_service import FluentBitTestService @@ -131,3 +136,91 @@ def test_out_loki_preserves_long_unicode_json_strings(): assert len(records) == RECORD_COUNT assert all(set(record) == {"msg"} for record in records) assert sorted(record["msg"] for record in records) == sorted(expected_messages) + + +class OAuthService: + def __init__(self, config_file): + test_directory = Path(__file__).resolve().parent + config_directory = test_directory.parent / "config" + cert_dir = test_directory.parent.parent / "in_splunk" / "certificate" + self.tls_crt_file = str(cert_dir / "certificate.pem") + self.tls_key_file = str(cert_dir / "private_key.pem") + self.service = FluentBitTestService( + str(config_directory / config_file), + data_storage=data_storage, + data_keys=["payloads", "requests"], + extra_env={ + "CERTIFICATE_TEST": self.tls_crt_file, + "PRIVATE_KEY_TEST": self.tls_key_file, + }, + pre_start=self._start_receiver, + post_stop=self._stop_receiver, + ) + + def _start_receiver(self, service): + http_server_run(service.test_suite_http_port) + self.service.wait_for_http_endpoint( + f"http://127.0.0.1:{service.test_suite_http_port}/ping", + timeout=10, + interval=0.5, + ) + + def _stop_receiver(self, service): + try: + requests.post( + f"http://127.0.0.1:{service.test_suite_http_port}/shutdown", + timeout=2, + ) + except requests.RequestException: + pass + + def start(self): + self.service.start() + + def stop(self): + self.service.stop() + + def wait_for_requests(self, minimum_count, timeout=10): + timeout = 60 if memory_check_enabled() else timeout + return self.service.wait_for_condition( + lambda: data_storage["requests"] if len(data_storage["requests"]) >= minimum_count else None, + timeout=timeout, + interval=0.5, + description=f"{minimum_count} requests", + ) + + +@pytest.mark.parametrize( + "config_file,auth_mode", + [ + ("out_loki_oauth2_basic.yaml", "basic"), + ("out_loki_oauth2_private_key_jwt.yaml", "private_key_jwt"), + ], + ids=["oauth2_basic", "oauth2_private_key_jwt"], +) +def test_out_loki_oauth2_auth_matrix(config_file, auth_mode): + service = OAuthService(config_file) + service.start() + configure_oauth_token_response( + status_code=200, + body={"access_token": "oauth-access-token", "token_type": "Bearer", "expires_in": 300}, + ) + + requests_seen = service.wait_for_requests(2) + service.stop() + + token_request = next(request for request in requests_seen if request["path"] == "/oauth/token") + data_request = next(request for request in requests_seen if request["path"] == "/loki/api/v1/push") + + assert token_request["method"] == "POST" + assert "grant_type=client_credentials" in token_request["raw_data"] + assert data_request["headers"].get("Authorization") == "Bearer oauth-access-token" + + if auth_mode == "basic": + assert "Basic " in token_request["headers"].get("Authorization", "") + assert "scope=logs.write" in token_request["raw_data"] + return + + assert "client_assertion_type=" in token_request["raw_data"] + assert "client_assertion=" in token_request["raw_data"] + assert "client_id=client1" in token_request["raw_data"] From cabc0ace5a109733c283a3940ba48a88b1ce8535 Mon Sep 17 00:00:00 2001 From: Umar Hussain Date: Sat, 12 Sep 2026 11:27:38 +0000 Subject: [PATCH 2/3] out_loki: apply suggestions from PR review Signed-off-by: Umar Hussain --- plugins/out_loki/loki.c | 13 ++++++- tests/runtime/out_loki.c | 81 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 93 insertions(+), 1 deletion(-) diff --git a/plugins/out_loki/loki.c b/plugins/out_loki/loki.c index c2adf44226b..35778ea0027 100644 --- a/plugins/out_loki/loki.c +++ b/plugins/out_loki/loki.c @@ -1147,7 +1147,8 @@ static struct flb_loki *loki_config_create(struct flb_output_instance *ins, ins->oauth2_config_map, &ctx->oauth2_config); if (ret == -1) { - flb_free(ctx); + loki_config_destroy(ctx); + flb_output_set_context(ins, NULL); return NULL; } @@ -1250,6 +1251,12 @@ static struct flb_loki *loki_config_create(struct flb_output_instance *ins, /* OAuth2 initialization */ if (ctx->oauth2_config.enabled == FLB_TRUE) { + if (ctx->http_user || ctx->http_passwd || ctx->bearer_token) { + flb_plg_error(ctx->ins, + "cannot use oauth2 with http_user/http_passwd or bearer_token"); + return NULL; + } + tmp_str = ctx->oauth2_auth_method ? ctx->oauth2_auth_method : flb_output_get_property("oauth2.auth_method", ins); @@ -2078,6 +2085,10 @@ static int send_loki_payload(struct flb_loki *ctx, /* Send HTTP request */ if (ctx->oauth2_ctx) { ret = flb_http_do_with_oauth2(c, &b_sent, ctx->oauth2_ctx); + /* on ouath retry orignal connection can be released and new connection is cleaned up later by u_conn */ + if (c->u_conn) { + u_conn = c->u_conn; + } } else { ret = flb_http_do(c, &b_sent); diff --git a/tests/runtime/out_loki.c b/tests/runtime/out_loki.c index 7873c7062fd..590c4ad13ca 100644 --- a/tests/runtime/out_loki.c +++ b/tests/runtime/out_loki.c @@ -1803,6 +1803,85 @@ void flb_test_structured_metadata_map_invalid_ra_key() { "[\"12345678000000000\",\"This is an interesting log message!\",{}]"); } +void flb_test_oauth2_auth_conflicts() +{ + int ret; + flb_ctx_t *ctx; + int in_ffd; + int out_ffd; + + /* 1. oauth2 + http_user/http_passwd conflict */ + ctx = flb_create(); + TEST_CHECK(ctx != NULL); + in_ffd = flb_input(ctx, (char *) "lib", NULL); + TEST_CHECK(in_ffd >= 0); + out_ffd = flb_output(ctx, (char *) "loki", NULL); + TEST_CHECK(out_ffd >= 0); + ret = flb_output_set(ctx, out_ffd, + "match", "*", + "host", "127.0.0.1", + "port", "3100", + "http_user", "user", + "http_passwd", "pass", + "oauth2.enable", "true", + "oauth2.token_url", "http://127.0.0.1:3100/token", + "oauth2.client_id", "client", + "oauth2.client_secret", "secret", + NULL); + TEST_CHECK(ret == 0); + ret = flb_start(ctx); + TEST_CHECK(ret != 0); + flb_destroy(ctx); + + /* 2. oauth2 + bearer_token conflict */ + ctx = flb_create(); + TEST_CHECK(ctx != NULL); + in_ffd = flb_input(ctx, (char *) "lib", NULL); + TEST_CHECK(in_ffd >= 0); + out_ffd = flb_output(ctx, (char *) "loki", NULL); + TEST_CHECK(out_ffd >= 0); + ret = flb_output_set(ctx, out_ffd, + "match", "*", + "host", "127.0.0.1", + "port", "3100", + "bearer_token", "token123", + "oauth2.enable", "true", + "oauth2.token_url", "http://127.0.0.1:3100/token", + "oauth2.client_id", "client", + "oauth2.client_secret", "secret", + NULL); + TEST_CHECK(ret == 0); + ret = flb_start(ctx); + TEST_CHECK(ret != 0); + flb_destroy(ctx); +} + +void flb_test_oauth2_invalid_config() +{ + int ret; + flb_ctx_t *ctx; + int in_ffd; + int out_ffd; + + /* oauth2 without token_url or client_id */ + ctx = flb_create(); + TEST_CHECK(ctx != NULL); + in_ffd = flb_input(ctx, (char *) "lib", NULL); + TEST_CHECK(in_ffd >= 0); + out_ffd = flb_output(ctx, (char *) "loki", NULL); + TEST_CHECK(out_ffd >= 0); + ret = flb_output_set(ctx, out_ffd, + "match", "*", + "host", "127.0.0.1", + "port", "3100", + "oauth2.enable", "true", + NULL); + TEST_CHECK(ret == 0); + ret = flb_start(ctx); + TEST_CHECK(ret != 0); + flb_destroy(ctx); +} + /* Test list */ TEST_LIST = { {"remove_keys_remove_map" , flb_test_remove_map}, @@ -1843,5 +1922,7 @@ TEST_LIST = { flb_test_structured_metadata_map_single_missing_map}, {"structured_metadata_map_invalid_ra_key", flb_test_structured_metadata_map_invalid_ra_key}, + {"oauth2_auth_conflicts", flb_test_oauth2_auth_conflicts}, + {"oauth2_invalid_config", flb_test_oauth2_invalid_config}, {NULL, NULL} }; From d0749f3cc3a1b3a1394574537874bc04afba2fdb Mon Sep 17 00:00:00 2001 From: Umar Hussain Date: Sat, 12 Sep 2026 11:50:42 +0000 Subject: [PATCH 3/3] out_loki: apply coderabbit fixes for cleanup if oauth config fails Signed-off-by: Umar Hussain --- plugins/out_loki/loki.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/plugins/out_loki/loki.c b/plugins/out_loki/loki.c index 35778ea0027..e2d4360bc6a 100644 --- a/plugins/out_loki/loki.c +++ b/plugins/out_loki/loki.c @@ -1254,6 +1254,8 @@ static struct flb_loki *loki_config_create(struct flb_output_instance *ins, if (ctx->http_user || ctx->http_passwd || ctx->bearer_token) { flb_plg_error(ctx->ins, "cannot use oauth2 with http_user/http_passwd or bearer_token"); + loki_config_destroy(ctx); + flb_output_set_context(ins, NULL); return NULL; } @@ -1272,11 +1274,15 @@ static struct flb_loki *loki_config_create(struct flb_output_instance *ins, } else { flb_plg_error(ctx->ins, "invalid oauth2.auth_method '%s'", tmp_str); + loki_config_destroy(ctx); + flb_output_set_context(ins, NULL); return NULL; } if (!ctx->oauth2_config.token_url || !ctx->oauth2_config.client_id) { flb_plg_error(ctx->ins, "oauth2 requires token_url and client_id"); + loki_config_destroy(ctx); + flb_output_set_context(ins, NULL); return NULL; } @@ -1285,17 +1291,23 @@ static struct flb_loki *loki_config_create(struct flb_output_instance *ins, !ctx->oauth2_config.jwt_cert_file) { flb_plg_error(ctx->ins, "oauth2 private_key_jwt requires " "jwt_key_file and jwt_cert_file"); + loki_config_destroy(ctx); + flb_output_set_context(ins, NULL); return NULL; } } else if (!ctx->oauth2_config.client_secret) { flb_plg_error(ctx->ins, "oauth2 basic/post require client_secret"); + loki_config_destroy(ctx); + flb_output_set_context(ins, NULL); return NULL; } ctx->oauth2_ctx = flb_oauth2_create_from_config(config, &ctx->oauth2_config); if (!ctx->oauth2_ctx) { flb_plg_error(ctx->ins, "failed to initialize oauth2 context"); + loki_config_destroy(ctx); + flb_output_set_context(ins, NULL); return NULL; } }