001/* 002 * oauth2-oidc-sdk 003 * 004 * Copyright 2012-2016, Connect2id Ltd and contributors. 005 * 006 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use 007 * this file except in compliance with the License. You may obtain a copy of the 008 * License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software distributed 013 * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 014 * CONDITIONS OF ANY KIND, either express or implied. See the License for the 015 * specific language governing permissions and limitations under the License. 016 */ 017 018package com.nimbusds.oauth2.sdk.token; 019 020 021import com.nimbusds.oauth2.sdk.ParseException; 022import com.nimbusds.oauth2.sdk.Scope; 023import com.nimbusds.oauth2.sdk.http.HTTPResponse; 024import net.jcip.annotations.Immutable; 025 026import java.net.URI; 027 028 029/** 030 * OAuth 2.0 bearer token error. Used to indicate that access to a resource 031 * protected by a Bearer access token is denied, due to the request or token 032 * being invalid, or due to the access token having insufficient scope. 033 * 034 * <p>Standard bearer access token errors: 035 * 036 * <ul> 037 * <li>{@link #MISSING_TOKEN} 038 * <li>{@link #INVALID_REQUEST} 039 * <li>{@link #INVALID_TOKEN} 040 * <li>{@link #INSUFFICIENT_SCOPE} 041 * </ul> 042 * 043 * <p>Example HTTP response: 044 * 045 * <pre> 046 * HTTP/1.1 401 Unauthorized 047 * WWW-Authenticate: Bearer realm="example.com", 048 * error="invalid_token", 049 * error_description="The access token expired" 050 * </pre> 051 * 052 * <p>Related specifications: 053 * 054 * <ul> 055 * <li>OAuth 2.0 Bearer Token Usage (RFC 6750) 056 * <li>Hypertext Transfer Protocol (HTTP/1.1): Authentication (RFC 7235) 057 * </ul> 058 */ 059@Immutable 060public class BearerTokenError extends TokenSchemeError { 061 062 063 private static final long serialVersionUID = -5209789923955060584L; 064 065 /** 066 * The request does not contain an access token. No error code or 067 * description is specified for this error, just the HTTP status code 068 * is set to 401 (Unauthorized). 069 * 070 * <p>Example: 071 * 072 * <pre> 073 * HTTP/1.1 401 Unauthorized 074 * WWW-Authenticate: Bearer 075 * </pre> 076 */ 077 public static final BearerTokenError MISSING_TOKEN = 078 new BearerTokenError(null, null, HTTPResponse.SC_UNAUTHORIZED); 079 080 081 /** 082 * The request is missing a required parameter, includes an unsupported 083 * parameter or parameter value, repeats the same parameter, uses more 084 * than one method for including an access token, or is otherwise 085 * malformed. The HTTP status code is set to 400 (Bad Request). 086 */ 087 public static final BearerTokenError INVALID_REQUEST = 088 new BearerTokenError("invalid_request", "Invalid request", 089 HTTPResponse.SC_BAD_REQUEST); 090 091 092 /** 093 * The access token provided is expired, revoked, malformed, or invalid 094 * for other reasons. The HTTP status code is set to 401 095 * (Unauthorized). 096 */ 097 public static final BearerTokenError INVALID_TOKEN = 098 new BearerTokenError("invalid_token", "Invalid access token", 099 HTTPResponse.SC_UNAUTHORIZED); 100 101 102 /** 103 * The request requires higher privileges than provided by the access 104 * token. The HTTP status code is set to 403 (Forbidden). 105 */ 106 public static final BearerTokenError INSUFFICIENT_SCOPE = 107 new BearerTokenError("insufficient_scope", "Insufficient scope", 108 HTTPResponse.SC_FORBIDDEN); 109 110 111 /** 112 * Creates a new OAuth 2.0 bearer token error with the specified code 113 * and description. 114 * 115 * @param code The error code, {@code null} if not specified. 116 * @param description The error description, {@code null} if not 117 * specified. 118 */ 119 public BearerTokenError(final String code, final String description) { 120 121 this(code, description, 0, null, null, null); 122 } 123 124 125 /** 126 * Creates a new OAuth 2.0 bearer token error with the specified code, 127 * description and HTTP status code. 128 * 129 * @param code The error code, {@code null} if not specified. 130 * @param description The error description, {@code null} if not 131 * specified. 132 * @param httpStatusCode The HTTP status code, zero if not specified. 133 */ 134 public BearerTokenError(final String code, final String description, final int httpStatusCode) { 135 136 this(code, description, httpStatusCode, null, null, null); 137 } 138 139 140 /** 141 * Creates a new OAuth 2.0 bearer token error with the specified code, 142 * description, HTTP status code, page URI, realm and scope. 143 * 144 * @param code The error code, {@code null} if not specified. 145 * @param description The error description, {@code null} if not 146 * specified. 147 * @param httpStatusCode The HTTP status code, zero if not specified. 148 * @param uri The error page URI, {@code null} if not 149 * specified. 150 * @param realm The realm, {@code null} if not specified. 151 * @param scope The required scope, {@code null} if not 152 * specified. 153 */ 154 public BearerTokenError(final String code, 155 final String description, 156 final int httpStatusCode, 157 final URI uri, 158 final String realm, 159 final Scope scope) { 160 161 super(AccessTokenType.BEARER, code, description, httpStatusCode, uri, realm, scope); 162 } 163 164 165 @Override 166 public BearerTokenError setDescription(final String description) { 167 168 return new BearerTokenError(super.getCode(), description, super.getHTTPStatusCode(), super.getURI(), getRealm(), getScope()); 169 } 170 171 172 @Override 173 public BearerTokenError appendDescription(final String text) { 174 175 String newDescription; 176 177 if (getDescription() != null) 178 newDescription = getDescription() + text; 179 else 180 newDescription = text; 181 182 return new BearerTokenError(super.getCode(), newDescription, super.getHTTPStatusCode(), super.getURI(), getRealm(), getScope()); 183 } 184 185 186 @Override 187 public BearerTokenError setHTTPStatusCode(final int httpStatusCode) { 188 189 return new BearerTokenError(super.getCode(), super.getDescription(), httpStatusCode, super.getURI(), getRealm(), getScope()); 190 } 191 192 193 @Override 194 public BearerTokenError setURI(final URI uri) { 195 196 return new BearerTokenError(super.getCode(), super.getDescription(), super.getHTTPStatusCode(), uri, getRealm(), getScope()); 197 } 198 199 200 @Override 201 public BearerTokenError setRealm(final String realm) { 202 203 return new BearerTokenError(getCode(), 204 getDescription(), 205 getHTTPStatusCode(), 206 getURI(), 207 realm, 208 getScope()); 209 } 210 211 212 @Override 213 public BearerTokenError setScope(final Scope scope) { 214 215 return new BearerTokenError(getCode(), 216 getDescription(), 217 getHTTPStatusCode(), 218 getURI(), 219 getRealm(), 220 scope); 221 } 222 223 224 /** 225 * Parses an OAuth 2.0 bearer token error from the specified HTTP 226 * response {@code WWW-Authenticate} header. 227 * 228 * @param wwwAuth The {@code WWW-Authenticate} header value to parse. 229 * Must not be {@code null}. 230 * 231 * @return The bearer token error. 232 * 233 * @throws ParseException If the {@code WWW-Authenticate} header value 234 * couldn't be parsed to a Bearer token error. 235 */ 236 public static BearerTokenError parse(final String wwwAuth) 237 throws ParseException { 238 239 TokenSchemeError genericError = TokenSchemeError.parse(wwwAuth, AccessTokenType.BEARER); 240 241 return new BearerTokenError( 242 genericError.getCode(), 243 genericError.getDescription(), 244 genericError.getHTTPStatusCode(), 245 genericError.getURI(), 246 genericError.getRealm(), 247 genericError.getScope() 248 ); 249 } 250}