001package com.nimbusds.oauth2.sdk;
002
003
004import java.net.URL;
005import java.util.Map;
006
007import net.jcip.annotations.Immutable;
008
009import com.nimbusds.oauth2.sdk.auth.ClientAuthentication;
010import com.nimbusds.oauth2.sdk.http.CommonContentTypes;
011import com.nimbusds.oauth2.sdk.http.HTTPRequest;
012import com.nimbusds.oauth2.sdk.util.URLUtils;
013
014
015/**
016 * Token request. Used to obtain an
017 * {@link com.nimbusds.oauth2.sdk.token.AccessToken access token} and an
018 * optional {@link com.nimbusds.oauth2.sdk.token.RefreshToken refresh token}
019 * at the Token endpoint of the authorisation server.
020 *
021 * <p>Example token request with an authorisation code grant:
022 *
023 * <pre>
024 * POST /token HTTP/1.1
025 * Host: server.example.com
026 * Content-Type: application/x-www-form-urlencoded
027 * Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW
028 * 
029 * grant_type=authorization_code
030 * &amp;code=SplxlOBeZQQYbYS6WxSbIA
031 * &amp;redirect_uri=https%3A%2F%2Fclient.example.org%2Fcb
032 * </pre>
033 *
034 * <p>Related specifications:
035 *
036 * <ul>
037 *     <li>OAuth 2.0 (RFC 6749), sections 4.1.3, 4.3.2, 4.4.2 and 6.
038 * </ul>
039 */
040@Immutable
041public class TokenRequest extends AbstractRequest {
042
043
044        /**
045         * The client authentication, {@code null} if none.
046         */
047        private final ClientAuthentication clientAuth;
048
049
050        /**
051         * The authorisation grant.
052         */
053        private final AuthorizationGrant authzGrant;
054        
055        
056        /**
057         * Creates a new token request.
058         *
059         * @param uri        The URI of the token endpoint. May be 
060         *                   {@code null} if the {@link #toHTTPRequest} method
061         *                   will not be used.
062         * @param clientAuth The client authentication, {@code null} if none.
063         * @param authzGrant The authorisation grant. Must not be {@code null}.
064         */
065        public TokenRequest(final URL uri,
066                            final ClientAuthentication clientAuth,
067                            final AuthorizationGrant authzGrant) {
068        
069                super(uri);
070                
071                this.clientAuth = clientAuth;
072
073                if (authzGrant == null)
074                        throw new IllegalArgumentException("The authorization grant must not be null");
075
076                this.authzGrant = authzGrant;
077        }
078        
079        
080        /**
081         * Gets the client authentication.
082         *
083         * @return The client authentication, {@code null} if none.
084         */
085        public ClientAuthentication getClientAuthentication() {
086        
087                return clientAuth;
088        }
089
090
091        /**
092         * Gets the authorisation grant.
093         *
094         * @return The authorisation grant.
095         */
096        public AuthorizationGrant getAuthorizationGrant() {
097
098                return authzGrant;
099        }
100
101
102        @Override
103        public HTTPRequest toHTTPRequest()
104                throws SerializeException {
105
106                if (getEndpointURI() == null)
107                        throw new SerializeException("The endpoint URI is not specified");
108
109                HTTPRequest httpRequest = new HTTPRequest(HTTPRequest.Method.POST, getEndpointURI());
110                httpRequest.setContentType(CommonContentTypes.APPLICATION_URLENCODED);
111
112                Map<String,String> params = authzGrant.toParameters();
113
114                httpRequest.setQuery(URLUtils.serializeParameters(params));
115
116                if (getClientAuthentication() != null)
117                        getClientAuthentication().applyTo(httpRequest);
118
119                return httpRequest;
120        }
121        
122        
123        /**
124         * Parses the specified HTTP request for a token request.
125         *
126         * @param httpRequest The HTTP request. Must not be {@code null}.
127         *
128         * @return The token request.
129         *
130         * @throws ParseException If the HTTP request couldn't be parsed to a 
131         *                        token request.
132         */
133        public static TokenRequest parse(final HTTPRequest httpRequest)
134                throws ParseException {
135                
136                // Only HTTP POST accepted
137                httpRequest.ensureMethod(HTTPRequest.Method.POST);
138                httpRequest.ensureContentType(CommonContentTypes.APPLICATION_URLENCODED);
139                
140                // No fragment!
141                // May use query component!
142                Map<String,String> params = httpRequest.getQueryParameters();
143
144                // Parse grant
145                AuthorizationGrant authzGrant = AuthorizationGrant.parse(params);
146
147                // Parse client auth
148                ClientAuthentication clientAuth = ClientAuthentication.parse(httpRequest);
149
150                return new TokenRequest(httpRequest.getURL(), clientAuth, authzGrant);
151        }
152}