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> getCustomParams() { 115 116 if (customParams == null) 117 return Collections.emptyMap(); 118 119 return Collections.unmodifiableMap(customParams); 120 } 121 122 123 /** 124 * Returns a JSON object representation of this access token response. 125 * 126 * <p>Example JSON object: 127 * 128 * <pre> 129 * { 130 * "access_token" : "SlAV32hkKG", 131 * "token_type" : "Bearer", 132 * "refresh_token" : "8xLOxBtZp8", 133 * "expires_in" : 3600 134 * } 135 * </pre> 136 * 137 * @return The JSON object. 138 */ 139 public JSONObject toJSONObject() { 140 141 JSONObject o = tokens.toJSONObject(); 142 143 if (customParams != null) 144 o.putAll(customParams); 145 146 return o; 147 } 148 149 150 @Override 151 public HTTPResponse toHTTPResponse() { 152 153 HTTPResponse httpResponse = new HTTPResponse(HTTPResponse.SC_OK); 154 155 httpResponse.setContentType(CommonContentTypes.APPLICATION_JSON); 156 httpResponse.setCacheControl("no-store"); 157 httpResponse.setPragma("no-cache"); 158 159 httpResponse.setContent(toJSONObject().toString()); 160 161 return httpResponse; 162 } 163 164 165 /** 166 * Parses an access token response from the specified JSON object. 167 * 168 * @param jsonObject The JSON object to parse. Must not be {@code null}. 169 * 170 * @return The access token response. 171 * 172 * @throws ParseException If the JSON object couldn't be parsed to an 173 * access token response. 174 */ 175 public static AccessTokenResponse parse(final JSONObject jsonObject) 176 throws ParseException { 177 178 Tokens tokens = Tokens.parse(jsonObject); 179 180 // Determine the custom param names 181 Set<String> paramNames = tokens.getParameterNames(); 182 Set<String> customParamNames = jsonObject.keySet(); 183 customParamNames.removeAll(paramNames); 184 185 Map<String,Object> customParams = null; 186 187 if (! customParamNames.isEmpty()) { 188 189 customParams = new HashMap<>(); 190 191 for (String name: customParamNames) { 192 customParams.put(name, jsonObject.get(name)); 193 } 194 } 195 196 return new AccessTokenResponse(tokens, customParams); 197 } 198 199 200 /** 201 * Parses an access token response from the specified HTTP response. 202 * 203 * @param httpResponse The HTTP response. Must not be {@code null}. 204 * 205 * @return The access token response. 206 * 207 * @throws ParseException If the HTTP response couldn't be parsed to an 208 * access token response. 209 */ 210 public static AccessTokenResponse parse(final HTTPResponse httpResponse) 211 throws ParseException { 212 213 httpResponse.ensureStatusCode(HTTPResponse.SC_OK); 214 JSONObject jsonObject = httpResponse.getContentAsJSONObject(); 215 return parse(jsonObject); 216 } 217}