36public final class TokenSpec {
40 private TokenSpec(
final Builder
builder) {
41 final Instant issuedAt = builder.issuedAt ==
null ? Instant.now() :
builder.issuedAt;
42 final Instant expiresAt = resolveExpiresAt(issuedAt,
builder.expiresAt,
builder.ttl);
45 throw new IllegalArgumentException(
"subject is required");
47 if (expiresAt ==
null) {
48 throw new IllegalArgumentException(
"expiresAt or ttl is required");
52 .issuedAt(issuedAt).expiresAt(expiresAt).notBefore(
builder.notBefore)
53 .jwtId(
builder.jwtId ==
null ||
builder.jwtId.isBlank() ? UUID.randomUUID().toString() :
builder.jwtId)
55 .extras(
builder.customClaims).build();
66 private static Instant resolveExpiresAt(
final Instant issuedAt,
final Instant expiresAt,
final Duration ttl) {
67 if (expiresAt !=
null) {
71 if (ttl.isNegative() || ttl.isZero()) {
72 throw new IllegalArgumentException(
"ttl must be > 0");
74 return issuedAt.plus(ttl);
79 public static final class Builder {
80 private String subject;
81 private String issuer;
82 private String[] audience;
83 private Instant issuedAt;
84 private Instant expiresAt;
86 private Instant notBefore;
88 private String[] roles;
89 private TokenType tokenType;
90 private String clientId;
91 private Map<String, Object> customClaims =
new LinkedHashMap<>();
96 public Builder subject(
final String subject) {
97 this.subject = subject;
101 public Builder issuer(
final String issuer) {
102 this.issuer = issuer;
106 public Builder audience(
final String... audience) {
107 this.audience = audience ==
null ?
new String[0] : audience;
111 public Builder issuedAt(
final Instant issuedAt) {
112 this.issuedAt = issuedAt;
116 public Builder expiresAt(
final Instant expiresAt) {
117 this.expiresAt = expiresAt;
121 public Builder ttl(
final Duration ttl) {
126 public Builder notBefore(
final Instant notBefore) {
127 this.notBefore = notBefore;
131 public Builder jwtId(
final String jwtId) {
136 public Builder roles(
final String... roles) {
137 this.roles = roles ==
null ?
new String[0] : roles;
141 public Builder tokenType(
final TokenType tokenType) {
142 this.tokenType = tokenType;
146 public Builder clientId(
final String clientId) {
147 this.clientId = clientId;
151 public Builder claim(
final String key,
final Object value) {
152 if (key ==
null || key.isBlank()) {
153 throw new IllegalArgumentException(
"claim key is required");
155 customClaims.put(key, value);
159 public Builder
claims(
final Map<String, Object> claims) {
160 customClaims = claims ==
null ?
new LinkedHashMap<>() : new LinkedHashMap<>(claims);
164 public TokenSpec build() {
165 return new TokenSpec(
this);