jio.http.client.oauth.ClientCredentialsClient Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jio-http Show documentation
Show all versions of jio-http Show documentation
Functional and reactive http client in Java
package jio.http.client.oauth;
import jio.IO;
import jio.Lambda;
import jio.http.client.HttpLambda;
import jio.http.client.JioHttpClient;
import jio.http.client.JioHttpClientBuilder;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.util.function.Function;
import java.util.function.Predicate;
/**
* An HTTP client with support for OAuth Client Credentials Grant. This client allows you to make HTTP requests with
* OAuth authentication using the Client Credentials Grant flow. It automatically handles access token expiration and
* refreshes tokens when needed.
*/
final class ClientCredentialsClient implements OauthHttpClient {
private static final int MAX_REFRESH_TOKEN_LOOP_SIZE = 3;
private final JioHttpClient httpClient;
private final Function>> accessTokenReq;
private final String authorizationHeaderName;
private final Function authorizationHeaderValue;
private final Lambda, String> getAccessToken;
private final Predicate> refreshTokenPredicate;
private final HttpLambda oauthStringLambda;
private final HttpLambda oauthBytesLambda;
private final HttpLambda ofStringLambda;
private final HttpLambda ofBytesLambda;
private final HttpLambda discardingLambda;
private final HttpLambda oauthDiscardingLambda;
private volatile String accessToken;
ClientCredentialsClient(final JioHttpClientBuilder client,
final Function>> accessTokenReq,
final String authorizationHeaderName,
final Function authorizationHeaderValue,
final Lambda, String> getAccessToken,
final Predicate> refreshTokenPredicate
) {
this.httpClient = client.get();
this.accessTokenReq = accessTokenReq;
this.authorizationHeaderName = authorizationHeaderName;
this.authorizationHeaderValue = authorizationHeaderValue;
this.getAccessToken = getAccessToken;
this.refreshTokenPredicate = refreshTokenPredicate;
this.ofStringLambda = httpClient.ofString();
this.ofBytesLambda = httpClient.ofBytes();
this.discardingLambda = httpClient.discarding();
this.oauthDiscardingLambda = builder -> oauthRequest(discardingLambda,
builder,
false,
0
);
this.oauthStringLambda = builder -> oauthRequest(ofStringLambda,
builder,
false,
0
);
this.oauthBytesLambda = builder -> oauthRequest(ofBytesLambda,
builder,
false,
0
);
}
@Override
public HttpLambda oauthOfString() {
return oauthStringLambda;
}
@Override
public HttpLambda oauthOfBytes() {
return oauthBytesLambda;
}
@Override
public HttpLambda oauthDiscarding() {
return oauthDiscardingLambda;
}
@Override
public HttpLambda oauthBodyHandler(HttpResponse.BodyHandler handler) {
return builder -> oauthRequest(bodyHandler(handler),
builder,
false,
0
);
}
@Override
public HttpLambda ofString() {
return ofStringLambda;
}
@Override
public HttpLambda ofBytes() {
return ofBytesLambda;
}
@Override
public HttpLambda discarding() {
return discardingLambda;
}
@Override
public HttpLambda bodyHandler(HttpResponse.BodyHandler handler) {
return httpClient.bodyHandler(handler);
}
private IO> oauthRequest(final HttpLambda httpLambda,
final HttpRequest.Builder builder,
final boolean refreshToken,
final int deep
) {
if (deep == MAX_REFRESH_TOKEN_LOOP_SIZE) {
return IO.fail(new RefreshTokenLoop(deep));
}
IO getToken = (refreshToken || this.accessToken == null) ?
accessTokenReq.apply(this)
.then(getAccessToken)
.peekSuccess(newToken -> this.accessToken = newToken) :
IO.succeed(this.accessToken);
return getToken.then(token ->
httpLambda.apply(builder.setHeader(authorizationHeaderName,
authorizationHeaderValue.apply(token)
)
)
.then(resp ->
refreshTokenPredicate.test(resp) ?
oauthRequest(httpLambda,
builder,
true,
deep + 1
) :
IO.succeed(resp)
)
);
}
}