private MultiValueMap<String, String> getParametersForTokenRequest(
      AuthorizationCodeResourceDetails resource, OAuth2SecurityContext context) {

    MultiValueMap<String, String> form = new LinkedMultiValueMap<String, String>();
    form.add("grant_type", "authorization_code");
    form.add("code", context.getAuthorizationCode());

    String redirectUri = resource.getPreEstablishedRedirectUri();
    if (context != null && redirectUri == null) {
      // no pre-established redirect uri: use the preserved state
      // TODO: treat redirect URI as a special kind of state (this is a historical mini hack)
      redirectUri = String.valueOf(context.getPreservedState());
    } else {
      // TODO: the state key is what should be sent, not the value
      form.add("state", String.valueOf(context.getPreservedState()));
    }

    if (redirectUri == null) {
      // still no redirect uri? just try the one for the current context...
      redirectUri = context == null ? null : context.getUserAuthorizationRedirectUri();
    }

    form.add("redirect_uri", redirectUri);

    return form;
  }
  public OAuth2AccessToken obtainNewAccessToken(OAuth2ProtectedResourceDetails details)
      throws UserRedirectRequiredException, AccessDeniedException {

    AuthorizationCodeResourceDetails resource = (AuthorizationCodeResourceDetails) details;
    OAuth2SecurityContext context = OAuth2SecurityContextHolder.getContext();

    if (context != null && context.getErrorParameters() != null) {

      // there was an oauth error...
      throw getSerializationService().deserializeError(context.getErrorParameters());

    } else if (context == null || context.getAuthorizationCode() == null) {

      throw getRedirectForAuthorization(resource, context);

    } else {

      return retrieveToken(getParametersForTokenRequest(resource, context), resource);
    }
  }