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