001package com.nimbusds.oauth2.sdk; 002 003 004import java.util.Collections; 005import java.util.HashMap; 006import java.util.Map; 007import java.util.Set; 008 009import net.jcip.annotations.Immutable; 010 011import net.minidev.json.JSONObject; 012 013import com.nimbusds.oauth2.sdk.token.Tokens; 014import com.nimbusds.oauth2.sdk.http.CommonContentTypes; 015import com.nimbusds.oauth2.sdk.http.HTTPResponse; 016 017 018/** 019 * Access token response from the Token endpoint. 020 * 021 * <p>Example HTTP response: 022 * 023 * <pre> 024 * HTTP/1.1 200 OK 025 * Content-Type: application/json;charset=UTF-8 026 * Cache-Control: no-store 027 * Pragma: no-cache 028 * 029 * { 030 * "access_token" : "2YotnFZFEjr1zCsicMWpAA", 031 * "token_type" : "example", 032 * "expires_in" : 3600, 033 * "refresh_token" : "tGzv3JOkF0XG5Qx2TlKWIA", 034 * "example_parameter" : "example_value" 035 * } 036 * </pre> 037 * 038 * <p>Related specifications: 039 * 040 * <ul> 041 * <li>OAuth 2.0 (RFC 6749), sections 4.1.4, 4.3.3, 4.4.3 and 5.1. 042 * </ul> 043 */ 044@Immutable 045public class AccessTokenResponse extends TokenResponse implements SuccessResponse { 046 047 048 /** 049 * The tokens. 050 */ 051 private final Tokens tokens; 052 053 054 /** 055 * Optional custom parameters. 056 */ 057 private final Map<String,Object> customParams; 058 059 060 /** 061 * Creates a new access token response. 062 * 063 * @param tokens The tokens. Must not be {@code null}. 064 */ 065 public AccessTokenResponse(final Tokens tokens) { 066 067 this(tokens, null); 068 } 069 070 071 /** 072 * Creates a new access token response. 073 * 074 * @param tokens The tokens. Must not be {@code null}. 075 * @param customParams Optional custom parameters, {@code null} if 076 * none. 077 */ 078 public AccessTokenResponse(final Tokens tokens, 079 final Map<String,Object> customParams) { 080 081 if (tokens == null) 082 throw new IllegalArgumentException("The tokens must not be null"); 083 084 this.tokens = tokens; 085 086 this.customParams = customParams; 087 } 088 089 090 @Override 091 public boolean indicatesSuccess() { 092 093 return true; 094 } 095 096 097 /** 098 * Returns the tokens. 099 * 100 * @return The tokens. 101 */ 102 public Tokens getTokens() { 103 104 return tokens; 105 } 106 107 108 /** 109 * Returns the custom parameters. 110 * 111 * @return The custom parameters, as a unmodifiable map, empty map if 112 * none. 113 */ 114 public Map<String,Object> getCustomParameters() { 115 116 if (customParams == null) 117 return Collections.emptyMap(); 118 119 return Collections.unmodifiableMap(customParams); 120 } 121 122 123 @Deprecated 124 public Map<String,Object> getCustomParams() { 125 126 return getCustomParameters(); 127 } 128 129 130 /** 131 * Returns a JSON object representation of this access token response. 132 * 133 * <p>Example JSON object: 134 * 135 * <pre> 136 * { 137 * "access_token" : "SlAV32hkKG", 138 * "token_type" : "Bearer", 139 * "refresh_token" : "8xLOxBtZp8", 140 * "expires_in" : 3600 141 * } 142 * </pre> 143 * 144 * @return The JSON object. 145 */ 146 public JSONObject toJSONObject() { 147 148 JSONObject o = tokens.toJSONObject(); 149 150 if (customParams != null) 151 o.putAll(customParams); 152 153 return o; 154 } 155 156 157 @Override 158 public HTTPResponse toHTTPResponse() { 159 160 HTTPResponse httpResponse = new HTTPResponse(HTTPResponse.SC_OK); 161 162 httpResponse.setContentType(CommonContentTypes.APPLICATION_JSON); 163 httpResponse.setCacheControl("no-store"); 164 httpResponse.setPragma("no-cache"); 165 166 httpResponse.setContent(toJSONObject().toString()); 167 168 return httpResponse; 169 } 170 171 172 /** 173 * Parses an access token response from the specified JSON object. 174 * 175 * @param jsonObject The JSON object to parse. Must not be {@code null}. 176 * 177 * @return The access token response. 178 * 179 * @throws ParseException If the JSON object couldn't be parsed to an 180 * access token response. 181 */ 182 public static AccessTokenResponse parse(final JSONObject jsonObject) 183 throws ParseException { 184 185 Tokens tokens = Tokens.parse(jsonObject); 186 187 // Determine the custom param names 188 Set<String> paramNames = tokens.getParameterNames(); 189 Set<String> customParamNames = jsonObject.keySet(); 190 customParamNames.removeAll(paramNames); 191 192 Map<String,Object> customParams = null; 193 194 if (! customParamNames.isEmpty()) { 195 196 customParams = new HashMap<>(); 197 198 for (String name: customParamNames) { 199 customParams.put(name, jsonObject.get(name)); 200 } 201 } 202 203 return new AccessTokenResponse(tokens, customParams); 204 } 205 206 207 /** 208 * Parses an access token response from the specified HTTP response. 209 * 210 * @param httpResponse The HTTP response. Must not be {@code null}. 211 * 212 * @return The access token response. 213 * 214 * @throws ParseException If the HTTP response couldn't be parsed to an 215 * access token response. 216 */ 217 public static AccessTokenResponse parse(final HTTPResponse httpResponse) 218 throws ParseException { 219 220 httpResponse.ensureStatusCode(HTTPResponse.SC_OK); 221 JSONObject jsonObject = httpResponse.getContentAsJSONObject(); 222 return parse(jsonObject); 223 } 224}