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