1 package com.guinetik.rr.auth;
2
3 import com.guinetik.rr.http.RocketHeaders;
4 import java.util.function.BooleanSupplier;
5
6 /**
7 * Authentication strategy that uses Bearer token authentication.
8 *
9 * <p>This strategy adds an {@code Authorization: Bearer <token>} header to all requests.
10 * It's suitable for APIs that use API keys, JWT tokens, or other bearer-style authentication.
11 *
12 * <h2>Basic Usage</h2>
13 * <pre class="language-java"><code>
14 * // Create via factory (recommended)
15 * AuthStrategy auth = AuthStrategyFactory.createBearerToken("my-api-token");
16 *
17 * // Configure client
18 * RocketRestConfig config = RocketRestConfig.builder("https://api.example.com")
19 * .authStrategy(auth)
20 * .build();
21 * </code></pre>
22 *
23 * <h2>With Custom Refresh Logic</h2>
24 * <p>For tokens that expire, you can provide custom refresh logic:
25 * <pre class="language-java"><code>
26 * AtomicReference<String> tokenRef = new AtomicReference<>("initial-token");
27 *
28 * AuthStrategy auth = AuthStrategyFactory.createBearerToken(tokenRef.get(), () -> {
29 * try {
30 * String newToken = myAuthService.refreshToken();
31 * tokenRef.set(newToken);
32 * return true;
33 * } catch (Exception e) {
34 * return false;
35 * }
36 * });
37 * </code></pre>
38 *
39 * <h2>For OAuth Tokens</h2>
40 * <p>If your bearer token comes from an OAuth flow, consider using the dedicated OAuth strategies
41 * which handle token refresh automatically:
42 * <ul>
43 * <li>{@link OAuth2ClientCredentialsStrategy}</li>
44 * <li>{@link OAuth2PasswordStrategy}</li>
45 * <li>{@link OAuth2AssertionStrategy}</li>
46 * </ul>
47 *
48 * @author guinetik <guinetik@gmail.com>
49 * @see AuthStrategy
50 * @see AuthStrategyFactory#createBearerToken(String)
51 * @since 1.0.0
52 */
53 public class BearerTokenStrategy implements AuthStrategy {
54
55 private final String token;
56 private final BooleanSupplier refreshTokenLogic;
57
58 /**
59 * Creates a new BearerTokenStrategy with no custom refresh logic.
60 * In this case, {@link #refreshCredentials()} will always return {@code false}.
61 *
62 * @param token the bearer token
63 */
64 public BearerTokenStrategy(String token) {
65 this(token, () -> false);
66 }
67
68 /**
69 * Creates a new BearerTokenStrategy with custom token refresh logic.
70 *
71 * @param token the bearer token
72 * @param refreshTokenLogic a {@link BooleanSupplier} that will be invoked by {@link #refreshCredentials()}.
73 * It should return {@code true} if the token was successfully refreshed, {@code false} otherwise.
74 */
75 public BearerTokenStrategy(String token, BooleanSupplier refreshTokenLogic) {
76 this.token = token;
77 this.refreshTokenLogic = refreshTokenLogic != null ? refreshTokenLogic : () -> false;
78 }
79
80 @Override
81 public AuthType getType() {
82 return AuthType.BEARER_TOKEN;
83 }
84
85 @Override
86 public RocketHeaders applyAuthHeaders(RocketHeaders headers) {
87 if (token != null && !token.isEmpty()) {
88 headers.bearerAuth(token);
89 }
90 return headers;
91 }
92
93 @Override
94 public boolean needsTokenRefresh() {
95 return false;
96 }
97
98 /**
99 * {@inheritDoc}
100 * <p>
101 * If a custom {@code refreshTokenLogic} was provided during construction,
102 * this method will invoke it and return its result.
103 * <p>
104 * If no custom logic was provided, this method always returns {@code false},
105 * as this strategy itself does not handle credential refresh.
106 */
107 @Override
108 public boolean refreshCredentials() {
109 return this.refreshTokenLogic.getAsBoolean();
110 }
111 }