Movatterモバイル変換


[0]ホーム

URL:


Akkadefault

JSON Web Tokens (JWT)

Akka’s JWT support is configured by placing annotations in your endpoints at the class level or method level.

Authentication

Akka can validate the signature of JWT tokens provided in an Authorization header to grant access to your endpoints. The generation of tokens is not provided by Akka. Inhttps://jwt.io/ you can find a simple way to generate tokens to start testing your services.

Bearer token validation

If you want to validate the bearer token of a request, you need to annotate your endpoint with a@JWT setting withJWT.JwtMethodMode.BEARER_TOKEN and you can add an issuer claim. Like this:

import akka.javasdk.annotations.JWT;import akka.javasdk.annotations.http.HttpEndpoint;@HttpEndpoint("/hello")@JWT(validate = JWT.JwtMethodMode.BEARER_TOKEN, bearerTokenIssuers = "my-issuer")(1)public class HelloJwtEndpoint extends AbstractHttpEndpoint {}
1Validate the Bearer is present in theAuthorization header and authorize only if the claimiss in the payload of this token ismy-issuer .

Requests are only allowed if they have a bearer token that can be validated by one of the configured keys for the service, all other requests will be rejected. The bearer token must be supplied with requests using theAuthorization header:

Authorization: Bearer eyJhbGciOiJIUzI1NiIsImtpZCI6ImtleTEifQ.eyJpc3MiOiJteS1pc3N1ZXIifQ.-MLcf1-kB_1OQIZdy9_wYiFZcMOHsHOE8aJryS1tWq4

You can check inhttps://jwt.io/ that this token contains the claim in the payloadiss: my-issuer.

It is recommended thatbearerTokenIssuers contains the issuer that you use in your JWT key configuration. Seehttps://doc.akka.io/security/jwts.html. Otherwise, any services with a trusted key can impersonate the issuer.

Configuring JWT at class level or method level

The above examples show how to configure a JWT token on a class or method level. When the annotation is present on both endpoint class and a method, the configuration on the method overrides the class configuration for that method.

Using more claims

Akka can be configured to automatically require and validate other claims than the issuer. MultipleStaticClaim can be declared and environment variables are supported on thevalues field. AStaticClaim can be defined both at class and method level. The provided claims will be used when validating against the bearer token.

@JWT(validate = JWT.JwtMethodMode.BEARER_TOKEN,    bearerTokenIssuers = "my-issuer",    staticClaims = {        @JWT.StaticClaim(claim = "role", values = {"admin", "editor"}),(1)        @JWT.StaticClaim(claim = "aud", values = "${ENV}.akka.io")})(2)
1When declaring multiple values for the same claim,all of them will be required when validating the request.
2The required value of theaud claim includes the value of environment variableENV

Seeakka service deploy -h for details on how to set environment variables when deploying a service.

For specifying an issuer claim (i.e. "iss"), you should still use thebearerTokenIssuers and not static claims.

Configuring claims with a pattern

Claims can also be defined using a pattern. This is useful when the value of the claim is not completely known in advance, but it can still be validated against a regular expression. See some examples below:

@JWT(validate = JWT.JwtMethodMode.BEARER_TOKEN,    bearerTokenIssuers = "my-issuer",    staticClaims = {        @JWT.StaticClaim(claim = "role", pattern = "^(admin|editor)$"),(1)        @JWT.StaticClaim(claim = "sub", pattern =(2)            "^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$"),        @JWT.StaticClaim(claim = "name", pattern = "^\\S+$")(3)    })
1Claim "role" must have one of 2 values:admin oreditor.
2Claim "sub" must be a valid UUID.
3Claim "name" must be not empty.

If the JWT token claim is an array of values, the token will be considered valid if at least one of the claim values matches the pattern. Otherwise, the request is rejected.

A claim can be defined with avalues or apattern, but not both.

Multiple issuers

Multiple issuers may be allowed, by setting multiplebearer_token_issuer values:

@JWT(validate = JWT.JwtMethodMode.BEARER_TOKEN, bearerTokenIssuers = {"my-issuer", "my-issuer2"}, staticClaims = @JWT.StaticClaim(claim = "sub", values = "my-subject"))

The token extracted from the bearer token must have one of the two issuers defined in the annotation.Akka will place the claims from the validated token in theRequestContext, so you can access them from your service viagetJwtClaims(). TheRequestContext is accessed by letting the endpoint extendAbstractHttpEndpoint which provides the methodrequestContext(), so you can retrieve the JWT claims like this:

import akka.javasdk.annotations.http.HttpEndpoint;import akka.javasdk.http.AbstractHttpEndpoint;public class HelloJwtEndpoint extends AbstractHttpEndpoint {  @JWT(validate = JWT.JwtMethodMode.BEARER_TOKEN, bearerTokenIssuers = {"my-issuer", "my-issuer2"}, staticClaims = @JWT.StaticClaim(claim = "sub", values = "my-subject"))  @Get("/claims")  public CompletionStage<String> helloClaims() {    var claims = requestContext().getJwtClaims();(1)    var issuer = claims.issuer().get();(2)    var sub = claims.subject().get();(2)    return completedStage("issuer: " + issuer + ", subject: " + sub);  }}
1Access the claims from the request context.
2Note that while callingOptional#get() is generally a bad practice, here we know the claims must be present given the@JWT configuration.

Running locally with JWTs enabled

When running locally, by default, a dev key with iddev is configured for use. This key uses the JWTnone signing algorithm, which means the signature of the received JWT tokens is not validated. Therefore, when calling an endpoint with a bearer token, only the presence and values of the claims are validated.

JWTs when running integration tests

When running integration tests, JWTs will still be enforced but its signature will not be validated, similarly to what is described above for when running locally. Thus, when making calls in the context of integration testing, make sure to inject a proper token with the required claims, as shown below:

@Testpublic void shouldReturnIssuerAndSubject() throws JsonProcessingException {  String bearerToken = bearerTokenWith(          Map.of("iss", "my-issuer", "sub", "my-subject"));(1)  CompletableFuture<StrictResponse<String>> call = httpClient.GET("/hello/claims").addHeader("Authorization","Bearer "+ bearerToken)(2)          .responseBodyAs(String.class)          .invokeAsync().toCompletableFuture();  Awaitility.await()          .ignoreExceptions()          .atMost(5, TimeUnit.SECONDS)          .untilAsserted(() -> {            assertThat(call.get().body()).isEqualTo("issuer: my-issuer, subject: my-subject");          });}private String bearerTokenWith(Map<String, String> claims) throws JsonProcessingException {  // setting algorithm to none  String header = Base64.getEncoder().encodeToString("""      {        "alg": "none"      }      """.getBytes());(3)  byte[] jsonClaims = new ObjectMapper().writeValueAsBytes(claims);  String payload = Base64.getEncoder().encodeToString(jsonClaims);  // no validation is done for integration tests, thus no signature required  return header + "." + payload;(4)}
1Use a helper method to create a JWT token with 2 claims: issuer and subject.
2Inject the bearer token as header with the keyAuthorization.
3Use staticBase64 encoding of{ "alg": "none" }.
4Note that you do not need to provide a signature, thus the token has only 2 parts, header and payload.

[8]ページ先頭

©2009-2025 Movatter.jp