001package com.nimbusds.oauth2.sdk; 002 003 004import java.net.URI; 005import java.net.URISyntaxException; 006import java.util.LinkedHashMap; 007import java.util.Map; 008 009import net.jcip.annotations.Immutable; 010 011 012/** 013 * Authorisation code grant. Used in access token requests with an 014 * authorisation code. 015 * 016 * <p>Related specifications: 017 * 018 * <ul> 019 * <li>OAuth 2.0 (RFC 6749), section 4.1.3. 020 * </ul> 021 */ 022@Immutable 023public final class AuthorizationCodeGrant extends AuthorizationGrant { 024 025 026 /** 027 * The grant type. 028 */ 029 public static final GrantType GRANT_TYPE = GrantType.AUTHORIZATION_CODE; 030 031 032 /** 033 * The authorisation code received from the authorisation server. 034 */ 035 private final AuthorizationCode code; 036 037 038 /** 039 * The conditionally required redirection URI in the initial 040 * authorisation request. 041 */ 042 private final URI redirectURI; 043 044 045 /** 046 * Creates a new authorisation code grant. 047 * 048 * @param code The authorisation code. Must not be {@code null}. 049 * @param redirectURI The redirection URI of the original authorisation 050 * request. Required if the {redirect_uri} 051 * parameter was included in the authorisation 052 * request, else {@code null}. 053 */ 054 public AuthorizationCodeGrant(final AuthorizationCode code, 055 final URI redirectURI) { 056 057 super(GRANT_TYPE); 058 059 if (code == null) 060 throw new IllegalArgumentException("The authorisation code must not be null"); 061 062 this.code = code; 063 064 this.redirectURI = redirectURI; 065 } 066 067 068 /** 069 * Gets the authorisation code. 070 * 071 * @return The authorisation code. 072 */ 073 public AuthorizationCode getAuthorizationCode() { 074 075 return code; 076 } 077 078 079 /** 080 * Gets the redirection URI of the original authorisation request. 081 * 082 * @return The redirection URI, {@code null} if the 083 * {@code redirect_uri} parameter was not included in the 084 * original authorisation request. 085 */ 086 public URI getRedirectionURI() { 087 088 return redirectURI; 089 } 090 091 092 @Override 093 public Map<String,String> toParameters() { 094 095 Map<String,String> params = new LinkedHashMap<>(); 096 params.put("grant_type", GRANT_TYPE.getValue()); 097 params.put("code", code.getValue()); 098 099 if (redirectURI != null) 100 params.put("redirect_uri", redirectURI.toString()); 101 102 return params; 103 } 104 105 106 /** 107 * Parses an authorisation code grant from the specified parameters. 108 * 109 * <p>Example: 110 * 111 * <pre> 112 * grant_type=authorization_code 113 * code=SplxlOBeZQQYbYS6WxSbIA 114 * redirect_uri=https://Fclient.example.com/cb 115 * </pre> 116 * 117 * @param params The parameters. 118 * 119 * @return The authorisation code grant. 120 * 121 * @throws ParseException If parsing failed. 122 */ 123 public static AuthorizationCodeGrant parse(final Map<String,String> params) 124 throws ParseException { 125 126 // Parse grant type 127 String grantTypeString = params.get("grant_type"); 128 129 if (grantTypeString == null) 130 throw new ParseException("Missing \"grant_type\" parameter", OAuth2Error.INVALID_REQUEST); 131 132 if (! GrantType.parse(grantTypeString).equals(GRANT_TYPE)) 133 throw new ParseException("The \"grant_type\" must be " + GRANT_TYPE, OAuth2Error.UNSUPPORTED_GRANT_TYPE); 134 135 // Parse authorisation code 136 String codeString = params.get("code"); 137 138 if (codeString == null || codeString.trim().isEmpty()) 139 throw new ParseException("Missing or empty \"code\" parameter", OAuth2Error.INVALID_REQUEST); 140 141 AuthorizationCode code = new AuthorizationCode(codeString); 142 143 // Parse optional redirection URI 144 String redirectURIString = params.get("redirect_uri"); 145 146 URI redirectURI = null; 147 148 if (redirectURIString != null) { 149 150 try { 151 redirectURI = new URI(redirectURIString); 152 } catch (URISyntaxException e) { 153 throw new ParseException("Invalid \"redirect_uri\" parameter: " + e.getMessage(), OAuth2Error.INVALID_REQUEST, e); 154 } 155 } 156 157 return new AuthorizationCodeGrant(code, redirectURI); 158 } 159}