Repository: slackapi/java-slack-sdk
Issue: MethodsClientImpl oauthV2Access: redirect_uri should be optional

### Issue Type
[ x ] Bug
[ ] Enhancement / Feature request
[ ] Question
[ ] Documentation

### Description

Hi @seratch !

I'm seeing this error when sending a null `redirect_uri` in `OauthV2AccessRequestBuilder`:

```
java.lang.IllegalArgumentException: Parameter specified as non-null is null: method okhttp3.FormBody$Builder.add, parameter value
```

It seems OKHTTP's form builder specifies that all param values must be non-null.

I think simply wrapping [this line](https://github.com/slackapi/java-slack-sdk/blob/master/slack-api-client/src/main/java/com/slack/api/methods/impl/MethodsClientImpl.java#L1698) in `MethodsClientImpl` with a null check should suffice:

```
if (req.getRedirectUri() != null) {
    form.add("redirect_uri", req.getRedirectUri());
}
```

Filing this as a bug due to a mismatch between [Slack's Oauth V2 api documentation](https://api.slack.com/methods/oauth.v2.access), which specifies `redirect_uri` as optional.

I should mention that I previously was using a hand-cooked Slack API client and Oauth worked fine without `redirect_uri`.

The issue is reproducible in:
* Module Version: 1.0.7
* JDK Version: Zulu 1.8.0_232

The steps to reproduce are:
1. Use the following sample (Kotlin) code with a valid `code`, `clientId`, and `clientSecret` (do not set `redirect_uri`):

```
    val builder = OAuthV2AccessRequest.builder()
        .code(code)				
        .clientId(clientId)
        .clientSecret(clientSecret)

    val response = methods.oauthV2Access(builder.build())
```

2. The expected result is the request should succeed.

3. The actual result is the following exception from OKHTTP:
```
java.lang.IllegalArgumentException: Parameter specified as non-null is null: method okhttp3.FormBody$Builder.add, parameter value
        at okhttp3.FormBody$Builder.add(FormBody.kt) ~[okhttp-4.6.0.jar!/:na]
        at com.slack.api.methods.impl.MethodsClientImpl.oauthV2Access(MethodsClientImpl.java:1638) ~[slack-api-client-1.0.7.jar!/:1.0.7]
```

Thank you for your amazing work!

* [ x ] I've read and understood the [Contributing guidelines](https://github.com/slackapi/java-slack-sdk/blob/master/.github/contributing.md) and have done my best effort to follow them.
* [ x ] I've read and agree to the [Code of Conduct](https://slackhq.github.io/code-of-conduct).
* [ x ] I've searched for any related issues and avoided creating a duplicate issue.

Changed files:
slack-api-client/src/main/java/com/slack/api/methods/impl/MethodsClientImpl.java, slack-api-client/src/test/java/test_locally/api/methods/OAuthTest.java

diff --git a/slack-api-client/src/main/java/com/slack/api/methods/impl/MethodsClientImpl.java b/slack-api-client/src/main/java/com/slack/api/methods/impl/MethodsClientImpl.java
index 5ba4851d..f8430ce0 100644
--- a/slack-api-client/src/main/java/com/slack/api/methods/impl/MethodsClientImpl.java
+++ b/slack-api-client/src/main/java/com/slack/api/methods/impl/MethodsClientImpl.java
@@ -1680,7 +1680,9 @@ public class MethodsClientImpl implements MethodsClient {
     public OAuthAccessResponse oauthAccess(OAuthAccessRequest req) throws IOException, SlackApiException {
         FormBody.Builder form = new FormBody.Builder();
         form.add("code", req.getCode());
-        form.add("redirect_uri", req.getRedirectUri());
+        if (req.getRedirectUri() != null) {
+            form.add("redirect_uri", req.getRedirectUri());
+        }
         form.add("single_channel", req.isSingleChannel() ? "1" : "0");
         String authorizationHeader = Credentials.basic(req.getClientId(), req.getClientSecret());
         return postFormWithAuthorizationHeaderAndParseResponse(form, endpointUrlPrefix + Methods.OAUTH_ACCESS, authorizationHeader, OAuthAccessResponse.class);
@@ -1695,7 +1697,9 @@ public class MethodsClientImpl implements MethodsClient {
     public OAuthV2AccessResponse oauthV2Access(OAuthV2AccessRequest req) throws IOException, SlackApiException {
         FormBody.Builder form = new FormBody.Builder();
         form.add("code", req.getCode());
-        form.add("redirect_uri", req.getRedirectUri());
+        if (req.getRedirectUri() != null) {
+            form.add("redirect_uri", req.getRedirectUri());
+        }
         String authorizationHeader = Credentials.basic(req.getClientId(), req.getClientSecret());
         return postFormWithAuthorizationHeaderAndParseResponse(form, endpointUrlPrefix + Methods.OAUTH_V2_ACCESS, authorizationHeader, OAuthV2AccessResponse.class);
     }
diff --git a/slack-api-client/src/test/java/test_locally/api/methods/OAuthTest.java b/slack-api-client/src/test/java/test_locally/api/methods/OAuthTest.java
index 33789709..0b0a2316 100644
--- a/slack-api-client/src/test/java/test_locally/api/methods/OAuthTest.java
+++ b/slack-api-client/src/test/java/test_locally/api/methods/OAuthTest.java
@@ -41,6 +41,13 @@ public class OAuthTest {
                 .isOk(), is(true));
     }
 
+    @Test
+    public void issue_474() throws Exception {
+        assertThat(slack.methods(ValidToken).oauthAccess(r -> r.clientId("abc").clientSecret("xyz").code("xxx")).isOk(), is(true));
+        assertThat(slack.methods(ValidToken).oauthToken(r -> r.clientId("abc").clientSecret("xyz").code("xxx")).isOk(), is(true));
+        assertThat(slack.methods(ValidToken).oauthV2Access(r -> r.clientId("abc").clientSecret("xyz").code("xxx")).isOk(), is(true));
+    }
+
     @Test
     public void test_async() throws Exception {
         assertThat(slack.methodsAsync(ValidToken).oauthAccess(r ->