001package com.nimbusds.oauth2.sdk;
002
003
004import java.net.URL;
005import java.util.LinkedHashMap;
006import java.util.Map;
007
008import net.jcip.annotations.Immutable;
009
010import com.nimbusds.oauth2.sdk.auth.ClientAuthentication;
011import com.nimbusds.oauth2.sdk.token.RefreshToken;
012import com.nimbusds.oauth2.sdk.http.CommonContentTypes;
013import com.nimbusds.oauth2.sdk.http.HTTPRequest;
014import com.nimbusds.oauth2.sdk.util.URLUtils;
015
016
017/**
018 * Refresh token request to the Token endpoint. Used to refresh an 
019 * {@link com.nimbusds.oauth2.sdk.token.AccessToken access token}. This class 
020 * is immutable.
021 *
022 * <p>Note that the optional scope parameter is not supported.
023 *
024 * <p>Example refresh token request:
025 *
026 * <pre>
027 * POST /token HTTP/1.1
028 * Host: server.example.com
029 * Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW
030 * Content-Type: application/x-www-form-urlencoded;charset=UTF-8
031 *
032 * grant_type=refresh_token&amp;refresh_token=tGzv3JOkF0XG5Qx2TlKWIA
033 * </pre>
034 *
035 * <p>Related specifications:
036 *
037 * <ul>
038 *     <li>OAuth 2.0 (RFC 6749), section 6.
039 * </ul>
040 *
041 * @author Vladimir Dzhuvinov
042 */
043@Immutable
044public final class RefreshTokenRequest extends TokenRequest {
045
046
047        /**
048         * The refresh token.
049         */
050        private final RefreshToken refreshToken;
051        
052        
053        /**
054         * Creates a new unauthenticated refresh token request.
055         *
056         * @param uri          The URI of the token endpoint. May be 
057         *                     {@code null} if the {@link #toHTTPRequest()}
058         *                     method will not be used.
059         * @param refreshToken The refresh token. Must not be {@code null}.
060         */
061        public RefreshTokenRequest(final URL uri, final RefreshToken refreshToken) {
062        
063                this(uri, refreshToken, null);
064        }
065        
066         
067        /**
068         * Creates a new authenticated refresh token request.
069         *
070         * @param uri          The URI of the token endpoint. May be 
071         *                     {@code null} if the {@link #toHTTPRequest()}
072         *                     method will not be used.
073         * @param refreshToken The refresh token. Must not be {@code null}.
074         * @param clientAuth   The client authentication, {@code null} if none.
075         */
076        public RefreshTokenRequest(final URL uri,
077                                   final RefreshToken refreshToken, 
078                                   final ClientAuthentication clientAuth) {
079        
080                super(uri, GrantType.REFRESH_TOKEN, clientAuth);
081                
082                if (refreshToken == null)
083                        throw new IllegalArgumentException("The refresh token must not be null");
084                
085                this.refreshToken = refreshToken;
086        }
087        
088        
089        /**
090         * Gets the refresh token.
091         *
092         * @return The refresh token.
093         */
094        public RefreshToken getRefreshToken() {
095        
096                return refreshToken;
097        }
098        
099        
100        @Override
101        public HTTPRequest toHTTPRequest()
102                throws SerializeException {
103                
104                if (getURI() == null)
105                        throw new SerializeException("The endpoint URI is not specified");
106                
107                HTTPRequest httpRequest = new HTTPRequest(HTTPRequest.Method.POST, getURI());
108                
109                httpRequest.setContentType(CommonContentTypes.APPLICATION_URLENCODED);
110                
111                Map<String,String> params = new LinkedHashMap<String,String>();
112                params.put("grant_type", getGrantType().toString());
113                params.put("refresh_token", refreshToken.getValue());
114                
115                httpRequest.setQuery(URLUtils.serializeParameters(params));
116                
117                if (getClientAuthentication() != null)
118                        getClientAuthentication().applyTo(httpRequest);
119                
120                return httpRequest;
121        }
122        
123        
124        /**
125         * Parses the specified HTTP request for a refresh token request.
126         *
127         * @param httpRequest The HTTP request. Must not be {@code null}.
128         *
129         * @return The refresh token request.
130         *
131         * @throws ParseException If the HTTP request couldn't be parsed to a 
132         *                        refresh token request.
133         */
134        public static RefreshTokenRequest parse(final HTTPRequest httpRequest)
135                throws ParseException {
136                
137                // Only HTTP POST accepted
138                httpRequest.ensureMethod(HTTPRequest.Method.POST);
139                httpRequest.ensureContentType(CommonContentTypes.APPLICATION_URLENCODED);
140                
141                // No fragment!
142                // May use query component!
143                
144                Map<String,String> params = httpRequest.getQueryParameters();
145                
146                
147                // Parse grant type
148                String grantTypeString = params.get("grant_type");
149                
150                if (grantTypeString == null)
151                        throw new ParseException("Missing \"grant_type\" parameter");
152
153                GrantType grantType = new GrantType(grantTypeString);
154                        
155                if (! grantType.equals(GrantType.REFRESH_TOKEN))
156                        throw new ParseException("Invalid \"grant_type\" parameter: " + grantTypeString);
157                
158                
159                // Parse refresh token
160                String tokenString = params.get("refresh_token");
161                
162                if (tokenString == null)
163                        throw new ParseException("Missing \"refresh_token\" parameter");
164                
165                // Parse client authentication
166                ClientAuthentication clientAuth = ClientAuthentication.parse(httpRequest);
167                
168                return new RefreshTokenRequest(URLUtils.getBaseURL(httpRequest.getURL()), 
169                                               new RefreshToken(tokenString), clientAuth);
170        }
171}