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