001package com.nimbusds.oauth2.sdk;
002
003
004import net.jcip.annotations.Immutable;
005
006import net.minidev.json.JSONObject;
007
008import com.nimbusds.oauth2.sdk.token.AccessToken;
009import com.nimbusds.oauth2.sdk.token.RefreshToken;
010import com.nimbusds.oauth2.sdk.token.TokenPair;
011import com.nimbusds.oauth2.sdk.http.CommonContentTypes;
012import com.nimbusds.oauth2.sdk.http.HTTPResponse;
013
014
015/**
016 * Access token response from the Token endpoint.
017 *
018 * <p>Example HTTP response:
019 *
020 * <pre>
021 * HTTP/1.1 200 OK
022 * Content-Type: application/json;charset=UTF-8
023 * Cache-Control: no-store
024 * Pragma: no-cache
025 *
026 * {
027 *   "access_token"      : "2YotnFZFEjr1zCsicMWpAA",
028 *   "token_type"        : "example",
029 *   "expires_in"        : 3600,
030 *   "refresh_token"     : "tGzv3JOkF0XG5Qx2TlKWIA",
031 *   "example_parameter" : "example_value"
032 * }
033 * </pre>
034 *
035 * <p>Related specifications:
036 *
037 * <ul>
038 *     <li>OAuth 2.0 (RFC 6749), sections 4.1.4, 4.3.3,  4.4.3 and 5.1.
039 * </ul>
040 */
041@Immutable
042public class AccessTokenResponse 
043        extends TokenResponse
044        implements SuccessResponse {
045
046
047        /**
048         * The access token.
049         */
050        private final AccessToken accessToken;
051        
052        
053        /**
054         * Optional refresh token.
055         */
056        private final RefreshToken refreshToken;
057        
058        
059        /**
060         * Creates a new access token response.
061         *
062         * @param accessToken  The access token. Must not be {@code null}.
063         * @param refreshToken Optional refresh token, {@code null} if none.
064         */
065        public AccessTokenResponse(final AccessToken accessToken,
066                                   final RefreshToken refreshToken) {
067                                   
068                if (accessToken == null)
069                        throw new IllegalArgumentException("The access token must not be null");
070                
071                this.accessToken = accessToken;
072                
073                this.refreshToken = refreshToken;
074        }
075
076
077        /**
078         * Creates a new access token response.
079         *
080         * @param tokenPair The access and refresh token pair. Must not be 
081         *                  {@code null}.
082         */
083        public AccessTokenResponse(final TokenPair tokenPair) {
084                                   
085                this(tokenPair.getAccessToken(), tokenPair.getRefreshToken());
086        }
087        
088        
089        /**
090         * Gets the access token.
091         *
092         * @return The access token.
093         */
094        public AccessToken getAccessToken() {
095        
096                return accessToken;
097        }
098        
099        
100        /**
101         * Gets the optional refresh token.
102         *
103         * @return The refresh token, {@code null} if none.
104         */
105        public RefreshToken getRefreshToken() {
106        
107                return refreshToken;
108        }
109
110
111        /**
112         * Gets the access and refresh token pair.
113         *
114         * @return The access and refresh token pair. Must not be {@code null}.
115         */
116        public TokenPair getTokenPair() {
117
118                return new TokenPair(accessToken, refreshToken);
119        }
120        
121        
122        /**
123         * Returns the JSON object representing this access token response.
124         *
125         * <p>Example JSON object:
126         *
127         * <pre>
128         * {
129         *   "access_token" : "SlAV32hkKG",
130         *   "token_type"   : "Bearer",
131         *   "refresh_token": "8xLOxBtZp8",
132         *   "expires_in"   : 3600
133         * }
134         * </pre>
135         *
136         * @return The JSON object.
137         *
138         * @throws SerializeException If this access token response couldn't be
139         *                            serialised to a JSON object.
140         */
141        public JSONObject toJSONObject()
142                throws SerializeException {
143        
144                JSONObject o = accessToken.toJSONObject();
145
146                if (refreshToken != null)
147                        o.putAll(refreshToken.toJSONObject());
148                
149                return o;
150        }
151        
152        
153        @Override
154        public HTTPResponse toHTTPResponse()
155                throws SerializeException {
156        
157                HTTPResponse httpResponse = new HTTPResponse(HTTPResponse.SC_OK);
158                
159                httpResponse.setContentType(CommonContentTypes.APPLICATION_JSON);
160                httpResponse.setCacheControl("no-store");
161                httpResponse.setPragma("no-cache");
162                
163                httpResponse.setContent(toJSONObject().toString());
164                
165                return httpResponse;
166        }
167        
168        
169        /**
170         * Parses an access token response from the specified JSON object.
171         *
172         * @param jsonObject The JSON object to parse. Must not be {@code null}.
173         *
174         * @return The access token response.
175         *
176         * @throws ParseException If the JSON object couldn't be parsed to an
177         *                        access token response.
178         */
179        public static AccessTokenResponse parse(final JSONObject jsonObject)
180                throws ParseException {
181                
182                AccessToken accessToken = AccessToken.parse(jsonObject);
183                
184                RefreshToken refreshToken = RefreshToken.parse(jsonObject);
185                
186                return new AccessTokenResponse(accessToken, refreshToken);
187        }
188        
189        
190        /**
191         * Parses an access token response from the specified HTTP response.
192         *
193         * @param httpResponse The HTTP response. Must not be {@code null}.
194         *
195         * @return The access token response.
196         *
197         * @throws ParseException If the HTTP response couldn't be parsed to an 
198         *                        access token response.
199         */
200        public static AccessTokenResponse parse(final HTTPResponse httpResponse)
201                throws ParseException {
202                
203                httpResponse.ensureStatusCode(HTTPResponse.SC_OK);
204                
205                JSONObject jsonObject = httpResponse.getContentAsJSONObject();
206                
207                return parse(jsonObject);
208        }
209}