diff --git a/src/Weatherstack/Security/OptionsTokenProvider.cs b/src/Weatherstack/Security/OptionsTokenProvider.cs
new file mode 100644
index 0000000..84e9aeb
--- /dev/null
+++ b/src/Weatherstack/Security/OptionsTokenProvider.cs
@@ -0,0 +1,82 @@
+// Copyright (c) 2024 tacosontitan
+// This file is part of the Weatherstack project, which is distributed under the MIT license.
+// See LICENSE for more information.
+
+using Microsoft.Extensions.Options;
+
+namespace Weatherstack.Security;
+
+///
+/// Represents a token provider that returns a token from an
+/// instance.
+///
+public sealed class OptionsTokenProvider
+ : ITokenProvider
+{
+ private string? _token;
+
+ ///
+ /// Creates a new instance focused
+ /// on the token provided by the specified .
+ ///
+ ///
+ /// The options to use for the token.
+ ///
+ public OptionsTokenProvider(IOptionsMonitor options)
+ {
+ #if NET6_0_OR_GREATER
+
+ ArgumentNullException.ThrowIfNull(options);
+
+ #else
+
+ if (options is null)
+ throw new ArgumentNullException(nameof(options));
+
+ #endif
+
+ _token = options.CurrentValue.Token;
+ options.OnChange(UpdateToken);
+
+ void UpdateToken(WeatherstackOptions options) =>
+ _token = options.Token;
+ }
+
+ ///
+ ///
+ /// Thrown when the token is .
+ ///
+ ///
+ /// Thrown when the token is empty or whitespace.
+ ///
+ public string GetToken()
+ {
+ ValidateToken(_token);
+ return _token!;
+ }
+
+ private static void ValidateToken(string? token)
+ {
+ #if NET6_0_OR_GREATER
+
+ ArgumentNullException.ThrowIfNull(token);
+
+ #else
+
+ if (token is null)
+ throw new ArgumentNullException(nameof(token));
+
+ #endif
+
+ #if NET8_0_OR_GREATER
+
+ ArgumentException.ThrowIfNullOrWhiteSpace(token);
+
+ #else
+
+ if (string.IsNullOrWhiteSpace(token))
+ throw new ArgumentException("The token cannot be empty or whitespace.", nameof(token));
+
+ #endif
+ }
+}