3838 */
3939public class CustomCredentialSupplierOktaWorkload {
4040
41- public static void main (String [] args ) throws IOException {
41+ public static void main (String [] args ) {
4242 // TODO(Developer): Replace these variables with your actual values.
4343 String gcpWorkloadAudience = System .getenv ("GCP_WORKLOAD_AUDIENCE" );
4444 String serviceAccountImpersonationUrl =
@@ -76,8 +76,7 @@ public static void customCredentialSupplierOktaWorkload(
7676 String gcsBucketName ,
7777 String oktaDomain ,
7878 String oktaClientId ,
79- String oktaClientSecret )
80- throws IOException {
79+ String oktaClientSecret ) {
8180 // 1. Instantiate our custom supplier with Okta credentials.
8281 OktaClientCredentialsSupplier oktaSupplier =
8382 new OktaClientCredentialsSupplier (oktaDomain , oktaClientId , oktaClientSecret );
@@ -143,21 +142,38 @@ public String getSubjectToken(ExternalAccountSupplierContext context) throws IOE
143142 }
144143
145144 /**
146- * Performs the Client Credentials grant flow by making a POST request to Okta's token
147- * endpoint.
145+ * Performs the Client Credentials grant flow by making a POST request to Okta's token endpoint.
146+ *
147+ * <p>To set up the Okta application for this flow:
148+ *
149+ * <ol>
150+ * <li>In your Okta developer console, create a new Application of type "Machine-to-Machine
151+ * (M2M)".
152+ * <li>Under the "General" tab, ensure that "Client Credentials" is an allowed grant type.
153+ * <li>Note the "Client ID" and "Client Secret" for your application.
154+ * <li>Navigate to "Security" > "API" and select your authorization server (e.g., "default").
155+ * <li>Under the "Scopes" tab, add a custom scope (e.g., "gcp.test.read").
156+ * <li>Ensure your M2M application is granted this scope.
157+ * </ol>
148158 */
149159 private void fetchOktaAccessToken () throws IOException {
150160 URL url = new URL (this .oktaTokenUrl );
151161 HttpURLConnection conn = (HttpURLConnection ) url .openConnection ();
152162 conn .setRequestMethod ("POST" );
153163 conn .setRequestProperty ("Content-Type" , "application/x-www-form-urlencoded" );
154164
165+ // The client_id and client_secret are sent in a Basic Auth header, as required by the
166+ // OAuth 2.0 Client Credentials grant specification. The credentials are Base64 encoded.
155167 String auth = this .clientId + ":" + this .clientSecret ;
156168 String encodedAuth = Base64 .getEncoder ().encodeToString (auth .getBytes (StandardCharsets .UTF_8 ));
157169 conn .setRequestProperty ("Authorization" , "Basic " + encodedAuth );
158170
159171 conn .setDoOutput (true );
160172 try (DataOutputStream out = new DataOutputStream (conn .getOutputStream ())) {
173+ // For the Client Credentials grant, scopes are optional and define the permissions
174+ // the access token will have. Replace "gcp.test.read" with the scopes defined in your
175+ // Okta authorization server. Multiple scopes can be requested by space-separating them
176+ // (e.g., "scope1 scope2").
161177 String params = "grant_type=client_credentials&scope=gcp.test.read" ;
162178 out .writeBytes (params );
163179 out .flush ();
@@ -194,4 +210,4 @@ private void fetchOktaAccessToken() throws IOException {
194210 }
195211 }
196212 }
197- }
213+ }
0 commit comments