001package com.nimbusds.openid.connect.sdk;
002
003
004import java.util.HashMap;
005import java.util.Map;
006
007import net.jcip.annotations.Immutable;
008
009import net.minidev.json.JSONObject;
010
011import com.nimbusds.oauth2.sdk.AccessTokenResponse;
012import com.nimbusds.oauth2.sdk.ParseException;
013import com.nimbusds.oauth2.sdk.http.HTTPResponse;
014import com.nimbusds.openid.connect.sdk.token.OIDCTokens;
015
016
017/**
018 * OpenID Connect token response from the Token endpoint.
019 *
020 * <p>Example HTTP response:
021 *
022 * <pre>
023 * HTTP/1.1 200 OK
024 * Content-Type: application/json
025 * Cache-Control: no-store
026 * Pragma: no-cache
027 * 
028 * {
029 *   "access_token"  : "SlAV32hkKG",
030 *   "token_type"    : "Bearer",
031 *   "refresh_token" : "8xLOxBtZp8",
032 *   "expires_in"    : 3600,
033 *   "id_token"      : "eyJhbGciOiJSUzI1NiJ9.eyJpc3MiOiJodHRwOlwvXC9zZXJ2Z
034 *    XIuZXhhbXBsZS5jb20iLCJ1c2VyX2lkIjoiMjQ4Mjg5NzYxMDAxIiwiYXVkIjoic
035 *    zZCaGRSa3F0MyIsIm5vbmNlIjoibi0wUzZfV3pBMk1qIiwiZXhwIjoxMzExMjgxO
036 *    TcwLCJpYXQiOjEzMTEyODA5NzB9.RgXxzppVvn1EjUiV3LIZ19SyhdyREe_2jJjW
037 *    5EC8XjNuJfe7Dte8YxRXxssJ67N8MT9mvOI3HOHm4whNx5FCyemyCGyTLHODCeAr
038 *    _id029-4JP0KWySoan1jmT7vbGHhu89-l9MTdaEvu7pNZO7DHGwqnMWRe8hdG7jU
039 *    ES4w4ReQTygKwXVVOaiGoeUrv6cZdbyOnpGlRlHaiOsv_xMunNVJtn5dLz-0zZwV
040 *    ftKVpFuc1pGaVsyZsOtkT32E4c6MDHeCvIDlR5ESC0ct8BLvGJDB5954MjCR4_X2
041 *    GAEHonKw4NF8wTmUFvhslYXmjRNFs21Byjn3jNb7lSa3MBfVsw"
042 * }
043 * </pre>
044 *
045 * <p>Related specifications:
046 *
047 * <ul>
048 *     <li>OpenID Connect Core 1.0, section 3.1.3.3.
049 *     <li>OAuth 2.0 (RFC 6749), sections 4.1.4 and 5.1.
050 * </ul>
051 */
052@Immutable
053public class OIDCTokenResponse extends AccessTokenResponse {
054
055
056        /**
057         * The OpenID Connect tokens.
058         */
059        private final OIDCTokens tokens;
060
061
062        /**
063         * Creates a new OpenID Connect access token response.
064         *
065         * @param tokens The OpenID Connect tokens. Must not be {@code null}.
066         */
067        public OIDCTokenResponse(final OIDCTokens tokens) {
068                                   
069                this(tokens, null);
070        }
071
072
073        /**
074         * Creates a new OpenID Connect access token response.
075         *
076         * @param tokens       The OpenID Connect tokens. Must not be
077         *                     {@code null}.
078         * @param customParams Optional custom parameters, {@code null} if
079         *                     none.
080         */
081        public OIDCTokenResponse(final OIDCTokens tokens,
082                                 final Map<String, Object> customParams) {
083
084                super(tokens, customParams);
085
086                this.tokens = tokens;
087        }
088
089
090        /**
091         * Gets the OpenID Connect tokens.
092         *
093         * @return The OpenID Connect tokens.
094         */
095        public OIDCTokens getOIDCTokens() {
096
097                return tokens;
098        }
099        
100        
101        /**
102         * Returns a JSON object representation of this OpenID Connect token
103         * response.
104         *
105         * <p>Example JSON object:
106         *
107         * <pre>
108         * {
109         *   "access_token" : "SlAV32hkKG",
110         *   "token_type"   : "Bearer",
111         *   "refresh_token": "8xLOxBtZp8",
112         *   "expires_in"   : 3600,
113         *   "id_token"     : "eyJ0 ... NiJ9.eyJ1c ... I6IjIifX0.DeWt4Qu ... ZXso"
114         * }
115         * </pre>
116         *
117         * @return The JSON object.
118         */
119        @Override
120        public JSONObject toJSONObject() {
121        
122                JSONObject o = super.toJSONObject();
123                o.put("id_token", getOIDCTokens().getIDTokenString());
124                return o;
125        }
126        
127        
128        /**
129         * Parses an OpenID Connect token response from the specified JSON
130         * object.
131         *
132         * @param jsonObject The JSON object to parse. Must not be 
133         *                   {@code null}.
134         *
135         * @return The OpenID Connect token response.
136         *
137         * @throws ParseException If the JSON object couldn't be parsed to an
138         *                        OpenID Connect token response.
139         */
140        public static OIDCTokenResponse parse(final JSONObject jsonObject)
141                throws ParseException {
142
143                OIDCTokens tokens = OIDCTokens.parse(jsonObject);
144
145                // Parse the custom parameters
146                Map<String,Object> customParams = new HashMap<>();
147                customParams.putAll(jsonObject);
148                for (String tokenParam: tokens.getParameterNames()) {
149                        customParams.remove(tokenParam);
150                }
151
152                if (customParams.isEmpty()) {
153                        return new OIDCTokenResponse(tokens);
154                }
155                
156                return new OIDCTokenResponse(tokens, customParams);
157        }
158        
159        
160        /**
161         * Parses an OpenID Connect access token response from the specified 
162         * HTTP response.
163         *
164         * @param httpResponse The HTTP response. Must not be {@code null}.
165         *
166         * @return The OpenID Connect access token response.
167         *
168         * @throws ParseException If the HTTP response couldn't be parsed to an 
169         *                        OpenID Connect access token response.
170         */
171        public static OIDCTokenResponse parse(final HTTPResponse httpResponse)
172                throws ParseException {
173                
174                httpResponse.ensureStatusCode(HTTPResponse.SC_OK);
175                JSONObject jsonObject = httpResponse.getContentAsJSONObject();
176                return parse(jsonObject);
177        }
178}