OAuth 2.0 client
Armeria can obtain an access token and attach it to outgoing requests as an
OAuth2Client decorator. The token grant API lives in the armeria-oauth2 module.
Supported grants
The client implements the following token requests:
- RFC 6749 Client Credentials
via
AccessTokenRequest.ofClientCredentials() - RFC 6749 Resource Owner Password Credentials
via
AccessTokenRequest.ofResourceOwnerPassword(). Legacy compatibility only; RFC 9700 §2.4 says this grant MUST NOT be used for new deployments. - RFC 7523 JSON Web Token (JWT) bearer assertions
via
AccessTokenRequest.ofJsonWebToken()
Dependency
- Gradle
- Gradle (Kotlin)
- Maven
dependencies {
implementation platform('com.linecorp.armeria:armeria-bom:1.42.0')
...
implementation 'com.linecorp.armeria:armeria-oauth2'
}
dependencies {
implementation(platform("com.linecorp.armeria:armeria-bom:1.42.0"))
...
implementation("com.linecorp.armeria:armeria-oauth2")
}
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.linecorp.armeria</groupId>
<artifactId>armeria-bom</artifactId>
<version>1.42.0</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
...
<dependency>
<groupId>com.linecorp.armeria</groupId>
<artifactId>armeria-oauth2</artifactId>
</dependency>
</dependencies>
A basic client
Build an OAuth2AuthorizationGrant against the authorization server's token endpoint, then
decorate the resource WebClient:
import java.time.Duration;
import com.linecorp.armeria.client.WebClient;
import com.linecorp.armeria.client.auth.oauth2.AccessTokenRequest;
import com.linecorp.armeria.client.auth.oauth2.OAuth2AuthorizationGrant;
import com.linecorp.armeria.client.auth.oauth2.OAuth2Client;
import com.linecorp.armeria.common.AggregatedHttpResponse;
WebClient authClient = WebClient.of("https://auth.example.com/");
AccessTokenRequest accessTokenRequest =
AccessTokenRequest.ofClientCredentials("client_id", "client_secret");
OAuth2AuthorizationGrant grant =
OAuth2AuthorizationGrant.builder(authClient, "/token")
.accessTokenRequest(accessTokenRequest)
.build();
WebClient client = WebClient.builder("https://api.example.com/")
.decorator(OAuth2Client.newDecorator(grant))
.build();
AggregatedHttpResponse res = client.get("/resource").aggregate().join();
OAuth2Client loads a token from the grant and sets the Authorization header on each
request. The first token is fetched lazily unless you call preload(true) on the grant builder.
Password and JWT grants use the same builder with a different AccessTokenRequest:
AccessTokenRequest passwordRequest =
AccessTokenRequest.ofResourceOwnerPassword("username", "password");
AccessTokenRequest jwtRequest =
AccessTokenRequest.ofJsonWebToken(signedJwt);
Refresh and token hooks
Use OAuth2AuthorizationGrantBuilder when you need to refresh earlier, persist tokens, or
fetch one at build time:
OAuth2AuthorizationGrant grant =
OAuth2AuthorizationGrant.builder(authClient, "/token")
.accessTokenRequest(accessTokenRequest)
.refreshBefore(Duration.ofMinutes(5))
.fallbackTokenProvider(() -> loadStoredToken())
.newTokenConsumer(token -> storeToken(token))
.preload(true)
.build();
refreshBefore— refresh this far before the token expires. The default is one minute.fallbackTokenProvider— tried before the first token request and after a failed issue or refresh.newTokenConsumer— invoked whenever a new token is issued, so you can store it for the fallback.preload(true)— request a token whenbuild()returns instead of on the first resource call.
Retry and circuit breaker
The token WebClient is a normal client. Decorate it if the authorization server should be
retried or short-circuited independently of the resource client:
import com.linecorp.armeria.client.circuitbreaker.CircuitBreakerClient;
import com.linecorp.armeria.client.circuitbreaker.CircuitBreakerRule;
import com.linecorp.armeria.client.retry.RetryRule;
import com.linecorp.armeria.client.retry.RetryingClient;
CircuitBreakerRule cbRule = CircuitBreakerRule.builder()
.onServerErrorStatus()
.onException()
.thenFailure();
WebClient authClient =
WebClient.builder("https://auth.example.com/")
.decorator(RetryingClient.newDecorator(RetryRule.failsafe()))
.decorator(CircuitBreakerClient.builder(cbRule).newDecorator())
.build();
OAuth2AuthorizationGrant grant =
OAuth2AuthorizationGrant.builder(authClient, "/token")
.accessTokenRequest(accessTokenRequest)
.build();
See Automatic retry and Circuit breaker for the full options.
You can also decorate the resource client. Add RetryingClient after OAuth2Client so
a failed token fetch can be retried with the resource request:
WebClient client =
WebClient.builder("https://api.example.com/")
.decorator(OAuth2Client.newDecorator(grant))
.decorator(RetryingClient.newDecorator(RetryRule.failsafe()))
.build();