Skip to content

Commit c050bf2

Browse files
authored
[SDK-4763] - add support for JAR and PAR with JAR to Authentication API (#636)
2 parents 0549138 + a0d3b57 commit c050bf2

2 files changed

Lines changed: 119 additions & 0 deletions

File tree

src/main/java/com/auth0/client/auth/AuthAPI.java

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -238,6 +238,25 @@ public String authorizeUrlWithPAR(String requestUri) {
238238
.toString();
239239
}
240240

241+
/**
242+
* Builds an authorization URL for JWT-Secured Authorization Request (JAR)
243+
* @param request the {@code request} parameter value. As specified, it must be a signed JWT and contain claims representing the authorization parameters.
244+
* @see AuthAPI#pushedAuthorizationRequestWithJAR(String)
245+
* @see <a href="https://auth0.com/docs/get-started/authentication-and-authorization-flow/authorization-code-flow/authorization-code-flow-with-jar">Authorization Code Flow with JWT-Secured Authorization Requests (JAR)</a>
246+
* @see <a href="https://datatracker.ietf.org/doc/html/rfc9101">RFC 9101</a>
247+
* @return the authorization URL to redirect users to for authentication.
248+
*/
249+
public String authorizeUrlWithJAR(String request) {
250+
Asserts.assertNotNull(request, "request");
251+
return baseUrl
252+
.newBuilder()
253+
.addPathSegment("authorize")
254+
.addQueryParameter("client_id", clientId)
255+
.addQueryParameter("request", request)
256+
.build()
257+
.toString();
258+
}
259+
241260
/**
242261
* Builds a request to make a Pushed Authorization Request (PAR) to receive a {@code request_uri} to send to the {@code /authorize} endpoint.
243262
* @param redirectUri the URL to redirect to after authorization has been granted by the user. Your Auth0 application
@@ -270,6 +289,33 @@ public Request<PushedAuthorizationResponse> pushedAuthorizationRequest(String re
270289
return request;
271290
}
272291

292+
/**
293+
* Builds a request to make a Pushed Authorization Request (PAR) with JWT-Secured Authorization Requests (JAR), to receive a {@code request_uri} to send to the {@code /authorize} endpoint.
294+
* @param request The signed JWT containing the authorization parameters as claims.
295+
* @see <a href="https://auth0.com/docs/get-started/authentication-and-authorization-flow/authorization-code-flow/authorization-code-flow-with-par-and-jar">Authorization Code Flow with PAR and JAR</a>
296+
* @see <a href="https://datatracker.ietf.org/doc/html/rfc9101">RFC 9101</a>
297+
* @see <a href="https://www.rfc-editor.org/rfc/rfc9126.html">RFC 9126</a>
298+
* @return a request to execute.
299+
*/
300+
public Request<PushedAuthorizationResponse> pushedAuthorizationRequestWithJAR(String request) {
301+
Asserts.assertNotNull(request, "request");
302+
303+
String url = baseUrl
304+
.newBuilder()
305+
.addPathSegments("oauth/par")
306+
.build()
307+
.toString();
308+
309+
FormBodyRequest<PushedAuthorizationResponse> req = new FormBodyRequest<>(client, null, url, HttpMethod.POST, new TypeReference<PushedAuthorizationResponse>() {});
310+
req.addParameter("client_id", clientId);
311+
req.addParameter("request", request);
312+
if (Objects.nonNull(this.clientSecret)) {
313+
req.addParameter("client_secret", clientSecret);
314+
}
315+
316+
return req;
317+
}
318+
273319
/**
274320
* Creates an instance of the {@link LogoutUrlBuilder} with the given return-to url.
275321
* i.e.:

src/test/java/com/auth0/client/auth/AuthAPITest.java

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1769,6 +1769,79 @@ public void shouldCreatePushedAuthorizationRequestWithoutSecret() throws Excepti
17691769
assertThat(response.getExpiresIn(), notNullValue());
17701770
}
17711771

1772+
@Test
1773+
public void authorizeUrlWithJARShouldThrowWhenRequestNull() {
1774+
verifyThrows(IllegalArgumentException.class,
1775+
() -> api.authorizeUrlWithJAR(null),
1776+
"'request' cannot be null!");
1777+
}
1778+
1779+
@Test
1780+
public void shouldBuildAuthorizeUrlWithJAR() {
1781+
String requestJwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJjbGllbnRfaWQiOiIxMjM0NTYiLCJyZWRpcmVjdF91cmkiOiJodHRwOi8vbG9jYWxob3N0OjMwMDAiLCJyZXNwb25zZV90eXBlIjoiY29kZSIsIm5vbmNlIjoiMTIzNCIsInN0YXRlIjoiNzhkeXVma2poZGYifQ.UQDz8hBIabaqatY75BvqGyiPoOqNYJQIsimUKg4_VrU";
1782+
AuthAPI api = AuthAPI.newBuilder("domain.auth0.com", CLIENT_ID, CLIENT_SECRET).build();
1783+
String url = api.authorizeUrlWithJAR("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJjbGllbnRfaWQiOiIxMjM0NTYiLCJyZWRpcmVjdF91cmkiOiJodHRwOi8vbG9jYWxob3N0OjMwMDAiLCJyZXNwb25zZV90eXBlIjoiY29kZSIsIm5vbmNlIjoiMTIzNCIsInN0YXRlIjoiNzhkeXVma2poZGYifQ.UQDz8hBIabaqatY75BvqGyiPoOqNYJQIsimUKg4_VrU");
1784+
assertThat(url, is(notNullValue()));
1785+
assertThat(url, isUrl("https", "domain.auth0.com", "/authorize"));
1786+
1787+
assertThat(url, hasQueryParameter("request", requestJwt));
1788+
assertThat(url, hasQueryParameter("client_id", CLIENT_ID));
1789+
}
1790+
1791+
@Test
1792+
public void pushedAuthorizationRequestShouldThrowWhenRequestIsNull() {
1793+
verifyThrows(IllegalArgumentException.class,
1794+
() -> api.pushedAuthorizationRequestWithJAR(null),
1795+
"'request' cannot be null!");
1796+
}
1797+
1798+
@Test
1799+
public void shouldCreatePushedAuthorizationJarRequest() throws Exception {
1800+
String requestJwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJjbGllbnRfaWQiOiIxMjM0NTYiLCJyZWRpcmVjdF91cmkiOiJodHRwOi8vbG9jYWxob3N0OjMwMDAiLCJyZXNwb25zZV90eXBlIjoiY29kZSIsIm5vbmNlIjoiMTIzNCIsInN0YXRlIjoiNzhkeXVma2poZGYifQ.UQDz8hBIabaqatY75BvqGyiPoOqNYJQIsimUKg4_VrU";
1801+
Request<PushedAuthorizationResponse> request = api.pushedAuthorizationRequestWithJAR(requestJwt);
1802+
assertThat(request, is(notNullValue()));
1803+
1804+
server.jsonResponse(PUSHED_AUTHORIZATION_RESPONSE, 200);
1805+
PushedAuthorizationResponse response = request.execute().getBody();
1806+
RecordedRequest recordedRequest = server.takeRequest();
1807+
1808+
assertThat(recordedRequest, hasMethodAndPath(HttpMethod.POST, "/oauth/par"));
1809+
assertThat(recordedRequest, hasHeader("Content-Type", "application/x-www-form-urlencoded"));
1810+
1811+
String body = readFromRequest(recordedRequest);
1812+
assertThat(body, containsString("client_id=" + CLIENT_ID));
1813+
assertThat(body, containsString("request=" + requestJwt));
1814+
assertThat(body, containsString("client_secret=" + CLIENT_SECRET));
1815+
1816+
assertThat(response, is(notNullValue()));
1817+
assertThat(response.getRequestURI(), not(emptyOrNullString()));
1818+
assertThat(response.getExpiresIn(), notNullValue());
1819+
}
1820+
1821+
@Test
1822+
public void shouldCreatePushedAuthorizationJarRequestWithoutSecret() throws Exception {
1823+
String requestJwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJjbGllbnRfaWQiOiIxMjM0NTYiLCJyZWRpcmVjdF91cmkiOiJodHRwOi8vbG9jYWxob3N0OjMwMDAiLCJyZXNwb25zZV90eXBlIjoiY29kZSIsIm5vbmNlIjoiMTIzNCIsInN0YXRlIjoiNzhkeXVma2poZGYifQ.UQDz8hBIabaqatY75BvqGyiPoOqNYJQIsimUKg4_VrU";
1824+
AuthAPI api = AuthAPI.newBuilder(server.getBaseUrl(), CLIENT_ID).build();
1825+
Request<PushedAuthorizationResponse> request = api.pushedAuthorizationRequestWithJAR(requestJwt);
1826+
assertThat(request, is(notNullValue()));
1827+
1828+
server.jsonResponse(PUSHED_AUTHORIZATION_RESPONSE, 200);
1829+
PushedAuthorizationResponse response = request.execute().getBody();
1830+
RecordedRequest recordedRequest = server.takeRequest();
1831+
1832+
assertThat(recordedRequest, hasMethodAndPath(HttpMethod.POST, "/oauth/par"));
1833+
assertThat(recordedRequest, hasHeader("Content-Type", "application/x-www-form-urlencoded"));
1834+
1835+
String body = readFromRequest(recordedRequest);
1836+
assertThat(body, containsString("client_id=" + CLIENT_ID));
1837+
assertThat(body, containsString("request=" + requestJwt));
1838+
assertThat(body, not(containsString("client_secret")));
1839+
1840+
assertThat(response, is(notNullValue()));
1841+
assertThat(response.getRequestURI(), not(emptyOrNullString()));
1842+
assertThat(response.getExpiresIn(), notNullValue());
1843+
}
1844+
17721845
static class TestAssertionSigner implements ClientAssertionSigner {
17731846

17741847
private final String token;

0 commit comments

Comments
 (0)