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.AccessToken; 014import com.nimbusds.oauth2.sdk.token.RefreshToken; 015import com.nimbusds.oauth2.sdk.token.TokenPair; 016import com.nimbusds.oauth2.sdk.http.CommonContentTypes; 017import com.nimbusds.oauth2.sdk.http.HTTPResponse; 018 019 020/** 021 * Access token response from the Token endpoint. 022 * 023 * <p>Example HTTP response: 024 * 025 * <pre> 026 * HTTP/1.1 200 OK 027 * Content-Type: application/json;charset=UTF-8 028 * Cache-Control: no-store 029 * Pragma: no-cache 030 * 031 * { 032 * "access_token" : "2YotnFZFEjr1zCsicMWpAA", 033 * "token_type" : "example", 034 * "expires_in" : 3600, 035 * "refresh_token" : "tGzv3JOkF0XG5Qx2TlKWIA", 036 * "example_parameter" : "example_value" 037 * } 038 * </pre> 039 * 040 * <p>Related specifications: 041 * 042 * <ul> 043 * <li>OAuth 2.0 (RFC 6749), sections 4.1.4, 4.3.3, 4.4.3 and 5.1. 044 * </ul> 045 */ 046@Immutable 047public class AccessTokenResponse 048 extends TokenResponse 049 implements SuccessResponse { 050 051 052 /** 053 * The access token. 054 */ 055 private final AccessToken accessToken; 056 057 058 /** 059 * Optional refresh token. 060 */ 061 private final RefreshToken refreshToken; 062 063 064 /** 065 * Optional custom parameters. 066 */ 067 private final Map<String,Object> customParams; 068 069 070 /** 071 * Creates a new access token response. 072 * 073 * @param accessToken The access token. Must not be {@code null}. 074 * @param refreshToken Optional refresh token, {@code null} if none. 075 */ 076 public AccessTokenResponse(final AccessToken accessToken, 077 final RefreshToken refreshToken) { 078 079 this(accessToken, refreshToken, null); 080 } 081 082 083 /** 084 * Creates a new access token response. 085 * 086 * @param accessToken The access token. Must not be {@code null}. 087 * @param refreshToken Optional refresh token, {@code null} if none. 088 * @param customParams Optional custom parameters, {@code null} if 089 * none. 090 */ 091 public AccessTokenResponse(final AccessToken accessToken, 092 final RefreshToken refreshToken, 093 final Map<String,Object> customParams) { 094 095 if (accessToken == null) 096 throw new IllegalArgumentException("The access token must not be null"); 097 098 this.accessToken = accessToken; 099 100 this.refreshToken = refreshToken; 101 102 this.customParams = customParams; 103 } 104 105 106 /** 107 * Creates a new access token response. 108 * 109 * @param tokenPair The access and refresh token pair. Must not be 110 * {@code null}. 111 */ 112 public AccessTokenResponse(final TokenPair tokenPair) { 113 114 this(tokenPair, null); 115 } 116 117 118 /** 119 * Creates a new access token response. 120 * 121 * @param tokenPair The access and refresh token pair. Must not be 122 * {@code null}. 123 * @param customParams Optional custom parameters, {@code null} if 124 * none. 125 */ 126 public AccessTokenResponse(final TokenPair tokenPair, 127 final Map<String,Object> customParams) { 128 129 this(tokenPair.getAccessToken(), tokenPair.getRefreshToken(), customParams); 130 } 131 132 133 /** 134 * Gets the access token. 135 * 136 * @return The access token. 137 */ 138 public AccessToken getAccessToken() { 139 140 return accessToken; 141 } 142 143 144 /** 145 * Gets the optional refresh token. 146 * 147 * @return The refresh token, {@code null} if none. 148 */ 149 public RefreshToken getRefreshToken() { 150 151 return refreshToken; 152 } 153 154 155 /** 156 * Gets the access and refresh token pair. 157 * 158 * @return The access and refresh token pair. Must not be {@code null}. 159 */ 160 public TokenPair getTokenPair() { 161 162 return new TokenPair(accessToken, refreshToken); 163 } 164 165 166 /** 167 * Gets the custom parameters. 168 * 169 * @return The custom parameters, as a unmodifiable map, empty map if 170 * none. 171 */ 172 public Map<String,Object> getCustomParams() { 173 174 if (customParams == null) 175 return Collections.emptyMap(); 176 177 return Collections.unmodifiableMap(customParams); 178 } 179 180 181 /** 182 * Returns the JSON object representing this access token response. 183 * 184 * <p>Example JSON object: 185 * 186 * <pre> 187 * { 188 * "access_token" : "SlAV32hkKG", 189 * "token_type" : "Bearer", 190 * "refresh_token": "8xLOxBtZp8", 191 * "expires_in" : 3600 192 * } 193 * </pre> 194 * 195 * @return The JSON object. 196 * 197 * @throws SerializeException If this access token response couldn't be 198 * serialised to a JSON object. 199 */ 200 public JSONObject toJSONObject() 201 throws SerializeException { 202 203 JSONObject o = accessToken.toJSONObject(); 204 205 if (refreshToken != null) 206 o.putAll(refreshToken.toJSONObject()); 207 208 if (customParams != null) 209 o.putAll(customParams); 210 211 return o; 212 } 213 214 215 @Override 216 public HTTPResponse toHTTPResponse() 217 throws SerializeException { 218 219 HTTPResponse httpResponse = new HTTPResponse(HTTPResponse.SC_OK); 220 221 httpResponse.setContentType(CommonContentTypes.APPLICATION_JSON); 222 httpResponse.setCacheControl("no-store"); 223 httpResponse.setPragma("no-cache"); 224 225 httpResponse.setContent(toJSONObject().toString()); 226 227 return httpResponse; 228 } 229 230 231 /** 232 * Parses an access token response from the specified JSON object. 233 * 234 * @param jsonObject The JSON object to parse. Must not be {@code null}. 235 * 236 * @return The access token response. 237 * 238 * @throws ParseException If the JSON object couldn't be parsed to an 239 * access token response. 240 */ 241 public static AccessTokenResponse parse(final JSONObject jsonObject) 242 throws ParseException { 243 244 AccessToken accessToken = AccessToken.parse(jsonObject); 245 246 RefreshToken refreshToken = RefreshToken.parse(jsonObject); 247 248 // Get the std param names for the access + refresh token 249 Set<String> paramNames = accessToken.getParamNames(); 250 251 if (refreshToken != null) 252 paramNames.addAll(refreshToken.getParamNames()); 253 254 // Determine the custom param names 255 Set<String> customParamNames = jsonObject.keySet(); 256 customParamNames.removeAll(paramNames); 257 258 Map<String,Object> customParams = null; 259 260 if (customParamNames.size() > 0) { 261 262 customParams = new HashMap<>(); 263 264 for (String name: customParamNames) { 265 customParams.put(name, jsonObject.get(name)); 266 } 267 } 268 269 return new AccessTokenResponse(accessToken, refreshToken, customParams); 270 } 271 272 273 /** 274 * Parses an access token response from the specified HTTP response. 275 * 276 * @param httpResponse The HTTP response. Must not be {@code null}. 277 * 278 * @return The access token response. 279 * 280 * @throws ParseException If the HTTP response couldn't be parsed to an 281 * access token response. 282 */ 283 public static AccessTokenResponse parse(final HTTPResponse httpResponse) 284 throws ParseException { 285 286 httpResponse.ensureStatusCode(HTTPResponse.SC_OK); 287 288 JSONObject jsonObject = httpResponse.getContentAsJSONObject(); 289 290 return parse(jsonObject); 291 } 292}