Okta Java SDK
認証ライブラリ
Okta Java SDK
概要
Okta Java SDKは、Javaアプリケーション向けの公式認証ライブラリです。Okta Identity EngineとClassic Engineの両方をサポートし、OAuth2、OpenID Connect、SAMLによる認証機能を提供します。管理SDK(okta-sdk-java)と認証SDK(okta-auth-java)の2つの主要コンポーネントを持ち、サーバーサイドコードでOktaの管理APIとの連携や、詳細な認証ワークフローの実装が可能です。
詳細
Okta Java SDKは、2024年7月に最新版がリリースされた活発に開発されているライブラリです。主要な特徴として、Identity Engine SDKによる最新のセキュリティ機能のサポート、Spring Bootとの統合機能、状態マシンベースの認証フロー管理があります。
2つの主要SDKには明確な役割分担があります。Management SDK(okta-sdk-java)は、Okta管理APIとの連携に使用し、ユーザー、グループ、アプリケーションの管理を行います。一方、Authentication SDK(okta-auth-java)は、認証ワークフローの詳細な制御を提供しますが、より多くの責任と保守作業が必要となります。多くのアプリケーションでは、OktaのホストサインインページまたはSign-in Widgetの使用が推奨されています。
Identity Engineへのアップグレード後は、既存のClassic Engine Javaライブラリと併用しながら、最新のIdentity Engine Java SDKパッケージを追加することが推奨されています。
メリット・デメリット
メリット
- 公式サポート: Oktaが公式に提供・保守する信頼性の高いライブラリ
- 包括的な機能: OAuth2、OIDC、SAMLなど主要な認証プロトコルをサポート
- Identity Engine対応: 最新のOktaプラットフォーム機能に対応
- Spring Boot統合: Spring Bootアプリケーションとのシームレスな統合
- 柔軟な実装: 管理機能と認証機能の両方を同一環境で利用可能
- アクティブな開発: 2024年も継続的にアップデートされている
デメリット
- 複雑な設定: 認証SDKを使用する場合の状態管理が複雑
- 学習コストの高さ: 状態マシンの概念と各状態のハンドラー実装が必要
- 保守負担: 詳細な認証ワークフローを実装する場合の保守コストが高い
- 依存関係: 多数の外部ライブラリへの依存
参考ページ
- Okta Developer SDKs
- GitHub - okta-sdk-java
- GitHub - okta-auth-java
- API Documentation
- Identity Engine SDK Guide
書き方の例
Maven依存関係の設定
<!-- Okta Management SDK -->
<dependency>
<groupId>com.okta.sdk</groupId>
<artifactId>okta-sdk-api</artifactId>
<version>19.0.0</version>
</dependency>
<dependency>
<groupId>com.okta.sdk</groupId>
<artifactId>okta-sdk-impl</artifactId>
<version>19.0.0</version>
<scope>runtime</scope>
</dependency>
<!-- Spring Boot統合(推奨) -->
<dependency>
<groupId>com.okta.spring</groupId>
<artifactId>okta-spring-sdk</artifactId>
<version>3.0.7</version>
</dependency>
<!-- Authentication SDK(高度な制御が必要な場合) -->
<dependency>
<groupId>com.okta.authn.sdk</groupId>
<artifactId>okta-authn-sdk-api</artifactId>
<version>2.0.1</version>
</dependency>
<dependency>
<groupId>com.okta.authn.sdk</groupId>
<artifactId>okta-authn-sdk-impl</artifactId>
<version>2.0.1</version>
<scope>runtime</scope>
</dependency>
基本的なManagement SDK使用例
import com.okta.sdk.client.Client;
import com.okta.sdk.client.Clients;
import com.okta.sdk.resource.user.User;
import com.okta.sdk.resource.user.UserBuilder;
import com.okta.sdk.resource.user.UserList;
public class OktaManagementExample {
public static void main(String[] args) {
// Oktaクライアントの初期化
Client client = Clients.builder()
.setOrgUrl("https://your-org.okta.com")
.setClientId("your-client-id")
.setPrivateKey("path/to/private-key.pem")
.build();
// ユーザー一覧の取得
UserList users = client.listUsers();
users.forEach(user -> {
System.out.println("User: " + user.getProfile().getLogin());
});
// 新しいユーザーの作成
User user = UserBuilder.instance()
.setEmail("[email protected]")
.setFirstName("New")
.setLastName("User")
.setLogin("[email protected]")
.setPassword("TempPassword123!".toCharArray())
.setActive(true)
.buildAndCreate(client);
System.out.println("Created user: " + user.getId());
}
}
Spring Boot設定例
// application.properties
/*
okta.oauth2.issuer=https://your-org.okta.com/oauth2/default
okta.oauth2.client-id=your-client-id
okta.oauth2.client-secret=your-client-secret
okta.oauth2.redirect-uri=/authorization-code/callback
okta.oauth2.post-logout-redirect-uri=http://localhost:8080/
*/
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(authz -> authz
.requestMatchers("/", "/home").permitAll()
.anyRequest().authenticated()
)
.oauth2Login(oauth2 -> oauth2
.defaultSuccessUrl("/dashboard", true)
)
.oauth2ResourceServer(oauth2 -> oauth2
.jwt(jwt -> jwt.decoder(jwtDecoder()))
);
return http.build();
}
@Bean
public JwtDecoder jwtDecoder() {
return OktaJwtDecoder.create(
"https://your-org.okta.com/oauth2/default"
);
}
}
Authentication SDKを使った詳細な認証制御
import com.okta.authn.sdk.client.AuthenticationClient;
import com.okta.authn.sdk.client.AuthenticationClients;
import com.okta.authn.sdk.resource.AuthenticationRequest;
import com.okta.authn.sdk.resource.AuthenticationResponse;
public class OktaAuthenticationExample {
private AuthenticationClient authClient;
public OktaAuthenticationExample() {
this.authClient = AuthenticationClients.builder()
.setOrgUrl("https://your-org.okta.com")
.build();
}
public void authenticateUser(String username, String password) {
try {
AuthenticationRequest request = authClient.instantiate(AuthenticationRequest.class)
.setUsername(username)
.setPassword(password.toCharArray());
AuthenticationResponse response = authClient.authenticate(request, null);
switch (response.getStatus()) {
case SUCCESS:
System.out.println("認証成功");
String sessionToken = response.getSessionToken();
// sessionTokenを使ってOktaセッションを作成
break;
case MFA_REQUIRED:
System.out.println("MFA認証が必要");
handleMfaChallenge(response);
break;
case PASSWORD_EXPIRED:
System.out.println("パスワードの更新が必要");
handlePasswordReset(response);
break;
default:
System.out.println("認証状態: " + response.getStatus());
}
} catch (Exception e) {
System.err.println("認証エラー: " + e.getMessage());
}
}
private void handleMfaChallenge(AuthenticationResponse response) {
// MFA要素の選択とチャレンジ処理
response.getFactors().forEach(factor -> {
System.out.println("利用可能なMFA: " + factor.getFactorType());
});
}
private void handlePasswordReset(AuthenticationResponse response) {
// パスワードリセット処理
System.out.println("パスワードリセットが必要です");
}
}
グループとアプリケーションの管理
import com.okta.sdk.resource.group.Group;
import com.okta.sdk.resource.group.GroupBuilder;
import com.okta.sdk.resource.application.Application;
public class OktaGroupAndAppManagement {
private Client client;
public OktaGroupAndAppManagement(Client client) {
this.client = client;
}
public void manageGroups() {
// グループの作成
Group group = GroupBuilder.instance()
.setName("Developers")
.setDescription("Development team members")
.buildAndCreate(client);
// ユーザーをグループに追加
User user = client.getUser("[email protected]");
user.addToGroup(group.getId());
// グループメンバーの一覧表示
group.listUsers().forEach(member -> {
System.out.println("Group member: " + member.getProfile().getLogin());
});
}
public void manageApplications() {
// アプリケーション一覧の取得
client.listApplications().forEach(app -> {
System.out.println("Application: " + app.getName());
System.out.println("Status: " + app.getStatus());
});
// 特定のアプリケーションにユーザーを割り当て
Application app = client.getApplication("app-id");
User user = client.getUser("[email protected]");
app.assignUserToApplication(user);
}
}
Identity Engine SDK使用例
import com.okta.idx.sdk.api.client.IDXAuthenticationWrapper;
import com.okta.idx.sdk.api.response.AuthenticationResponse;
import com.okta.idx.sdk.api.model.AuthenticationOptions;
public class IdentityEngineExample {
private IDXAuthenticationWrapper authWrapper;
public IdentityEngineExample() {
this.authWrapper = new IDXAuthenticationWrapper(
"your-client-id",
"your-client-secret",
"https://your-org.okta.com",
"http://localhost:8080/callback"
);
}
public void performAuthentication(String username, String password) {
try {
AuthenticationOptions authOptions = new AuthenticationOptions(username, password);
AuthenticationResponse response = authWrapper.authenticate(authOptions, null);
if (response.isLoginSuccessful()) {
System.out.println("認証成功");
String accessToken = response.getTokenResponse().getAccessToken();
System.out.println("Access Token: " + accessToken);
} else {
System.out.println("追加の認証ステップが必要: " + response.getAuthenticationStatus());
}
} catch (Exception e) {
System.err.println("認証エラー: " + e.getMessage());
}
}
}
エラーハンドリングとログ設定
import com.okta.sdk.error.ResourceException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class OktaErrorHandling {
private static final Logger logger = LoggerFactory.getLogger(OktaErrorHandling.class);
private Client client;
public void handleOktaErrors() {
try {
User user = client.getUser("[email protected]");
} catch (ResourceException e) {
switch (e.getStatus()) {
case 404:
logger.warn("ユーザーが見つかりません: {}", e.getMessage());
break;
case 429:
logger.warn("レート制限に達しました: {}", e.getMessage());
// リトライロジックの実装
break;
case 401:
logger.error("認証エラー: {}", e.getMessage());
break;
default:
logger.error("Oktaエラー ({}): {}", e.getStatus(), e.getMessage());
}
} catch (Exception e) {
logger.error("予期しないエラー: {}", e.getMessage(), e);
}
}
}
設定ファイル管理
// ~/.okta/okta.yaml
/*
okta:
client:
orgUrl: "https://your-org.okta.com"
token: "your-api-token"
# または環境変数
# OKTA_CLIENT_ORGURL=https://your-org.okta.com
# OKTA_CLIENT_TOKEN=your-api-token
*/
@Configuration
public class OktaConfig {
@Bean
public Client oktaClient() {
return Clients.builder()
.setOrgUrl(System.getenv("OKTA_CLIENT_ORGURL"))
.setClientId(System.getenv("OKTA_CLIENT_CLIENTID"))
.setPrivateKey(System.getenv("OKTA_CLIENT_PRIVATE_KEY"))
.build();
}
}