Skip to content

Commit 553c156

Browse files
authored
[SDK-4400] Support Organization Name on Authorize URL (#550)
1 parent 084187e commit 553c156

3 files changed

Lines changed: 152 additions & 20 deletions

File tree

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ public AuthorizeUrlBuilder withResponseType(String responseType) {
109109
/**
110110
* Sets the organization query string parameter value used to login to an organization.
111111
*
112-
* @param organization The ID of the organization to log the user in to.
112+
* @param organization The ID or name of the organization to log the user in to.
113113
* @return the builder instance.
114114
*/
115115
public AuthorizeUrlBuilder withOrganization(String organization) {

src/main/java/com/auth0/utils/tokens/IdTokenVerifier.java

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -138,14 +138,26 @@ public void verify(String token, String nonce, Integer maxAuthenticationAge) thr
138138

139139
// Org verification
140140
if (this.organization != null) {
141-
String orgClaim = decoded.getClaim("org_id").asString();
142-
if (isEmpty(orgClaim)) {
143-
throw new IdTokenValidationException("Organization Id (org_id) claim must be a string present in the ID token");
141+
String org = this.organization.trim();
142+
if (org.startsWith("org_")) {
143+
// org ID
144+
String orgClaim = decoded.getClaim("org_id").asString();
145+
if (isEmpty(orgClaim)) {
146+
throw new IdTokenValidationException("Organization Id (org_id) claim must be a string present in the ID token");
147+
}
148+
if (!this.organization.equals(orgClaim)) {
149+
throw new IdTokenValidationException(String.format("Organization (org_id) claim mismatch in the ID token; expected \"%s\" but found \"%s\"", this.organization, orgClaim));
150+
}
151+
} else {
152+
// org name
153+
String orgNameClaim = decoded.getClaim("org_name").asString();
154+
if (isEmpty(orgNameClaim)) {
155+
throw new IdTokenValidationException("Organization name (org_name) claim must be a string present in the ID token");
156+
}
157+
if (!org.toLowerCase().equals(orgNameClaim)) {
158+
throw new IdTokenValidationException(String.format("Organization (org_name) claim mismatch in the ID token; expected \"%s\" but found \"%s\"", this.organization, orgNameClaim));
159+
}
144160
}
145-
if (!this.organization.equals(orgClaim)) {
146-
throw new IdTokenValidationException(String.format("Organization (org_id) claim mismatch in the ID token; expected \"%s\" but found \"%s\"", this.organization, orgClaim));
147-
}
148-
149161
}
150162

151163
final Calendar cal = Calendar.getInstance();

src/test/java/com/auth0/utils/tokens/IdTokenVerifierTest.java

Lines changed: 132 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -420,7 +420,87 @@ public void succeedsWithValidTokenUsingDefaultClockAndHttpsDomain() {
420420
}
421421

422422
@Test
423-
public void succeedsWhenOrganizationMatchesExpected() {
423+
public void succeedsWhenOrganizationNamdMatchesExpected() {
424+
String token = JWT.create()
425+
.withSubject("auth0|sdk458fks")
426+
.withAudience(AUDIENCE)
427+
.withIssuedAt(getYesterday())
428+
.withExpiresAt(getTomorrow())
429+
.withIssuer("https://" + DOMAIN + "/")
430+
.withClaim("org_name", "my org")
431+
.sign(Algorithm.HMAC256("secret"));
432+
433+
String jwt = JWT.decode(token).getToken();
434+
435+
configureVerifier(jwt)
436+
.withOrganization("my org")
437+
.build()
438+
.verify(jwt);
439+
}
440+
441+
@Test
442+
public void failsWhenOrganizationNameDoesNotMatchExpected() {
443+
String token = JWT.create()
444+
.withSubject("auth0|sdk458fks")
445+
.withAudience(AUDIENCE)
446+
.withIssuedAt(getYesterday())
447+
.withExpiresAt(getTomorrow())
448+
.withIssuer("https://" + DOMAIN + "/")
449+
.withClaim("org_name", "my org")
450+
.sign(Algorithm.HMAC256("secret"));
451+
452+
String jwt = JWT.decode(token).getToken();
453+
454+
AssertsUtil.verifyThrows(IdTokenValidationException.class,
455+
() -> configureVerifier(jwt)
456+
.withOrganization("your org")
457+
.build()
458+
.verify(jwt),
459+
"Organization (org_name) claim mismatch in the ID token; expected \"your org\" but found \"my org\"");
460+
}
461+
462+
@Test
463+
public void failsWhenOrganizationNameExpectedButClaimIsNotString() {
464+
String token = JWT.create()
465+
.withSubject("auth0|sdk458fks")
466+
.withAudience(AUDIENCE)
467+
.withIssuedAt(getYesterday())
468+
.withExpiresAt(getTomorrow())
469+
.withIssuer("https://" + DOMAIN + "/")
470+
.withClaim("org_name", 42)
471+
.sign(Algorithm.HMAC256("secret"));
472+
473+
String jwt = JWT.decode(token).getToken();
474+
475+
AssertsUtil.verifyThrows(IdTokenValidationException.class, () -> {
476+
configureVerifier(jwt)
477+
.withOrganization("my org")
478+
.build()
479+
.verify(jwt);
480+
},
481+
"Organization name (org_name) claim must be a string present in the ID token");
482+
}
483+
484+
@Test
485+
public void succeedsWhenOrganizationNameNotSpecifiedButIsPresent() {
486+
String token = JWT.create()
487+
.withSubject("auth0|sdk458fks")
488+
.withAudience(AUDIENCE)
489+
.withIssuedAt(getYesterday())
490+
.withExpiresAt(getTomorrow())
491+
.withIssuer("https://" + DOMAIN + "/")
492+
.withClaim("org_name", "my org")
493+
.sign(Algorithm.HMAC256("secret"));
494+
495+
String jwt = JWT.decode(token).getToken();
496+
497+
configureVerifier(jwt)
498+
.build()
499+
.verify(jwt);
500+
}
501+
502+
@Test
503+
public void succeedsWhenOrganizationIdMatchesExpected() {
424504
String token = JWT.create()
425505
.withSubject("auth0|sdk458fks")
426506
.withAudience(AUDIENCE)
@@ -439,7 +519,7 @@ public void succeedsWhenOrganizationMatchesExpected() {
439519
}
440520

441521
@Test
442-
public void failsWhenOrganizationDoesNotMatchExpected() {
522+
public void failsWhenOrganizationIdDoesNotMatchExpected() {
443523
String token = JWT.create()
444524
.withSubject("auth0|sdk458fks")
445525
.withAudience(AUDIENCE)
@@ -453,34 +533,74 @@ public void failsWhenOrganizationDoesNotMatchExpected() {
453533

454534
AssertsUtil.verifyThrows(IdTokenValidationException.class,
455535
() -> configureVerifier(jwt)
456-
.withOrganization("org_abc")
457-
.build()
458-
.verify(jwt),
536+
.withOrganization("org_abc")
537+
.build()
538+
.verify(jwt),
459539
"Organization (org_id) claim mismatch in the ID token; expected \"org_abc\" but found \"org_123\"");
460540
}
461541

462542
@Test
463-
public void failsWhenOrganizationExpectedButNotPresent() {
543+
public void failsWhenOrganizationIdDoesNotMatchExpected_caseSensitive() {
464544
String token = JWT.create()
465545
.withSubject("auth0|sdk458fks")
466546
.withAudience(AUDIENCE)
467547
.withIssuedAt(getYesterday())
468548
.withExpiresAt(getTomorrow())
469549
.withIssuer("https://" + DOMAIN + "/")
550+
.withClaim("org_id", "oRg_123")
470551
.sign(Algorithm.HMAC256("secret"));
471552

472553
String jwt = JWT.decode(token).getToken();
473554

474555
AssertsUtil.verifyThrows(IdTokenValidationException.class,
475556
() -> configureVerifier(jwt)
476-
.withOrganization("org_123")
477-
.build()
478-
.verify(jwt),
557+
.withOrganization("org_123")
558+
.build()
559+
.verify(jwt),
560+
"Organization (org_id) claim mismatch in the ID token; expected \"org_123\" but found \"oRg_123\"");
561+
}
562+
563+
@Test
564+
public void failsWhenOrganizationIdExpectedButNotPresent() {
565+
String token = JWT.create()
566+
.withSubject("auth0|sdk458fks")
567+
.withAudience(AUDIENCE)
568+
.withIssuedAt(getYesterday())
569+
.withExpiresAt(getTomorrow())
570+
.withIssuer("https://" + DOMAIN + "/")
571+
.sign(Algorithm.HMAC256("secret"));
572+
573+
String jwt = JWT.decode(token).getToken();
574+
575+
AssertsUtil.verifyThrows(IdTokenValidationException.class,
576+
() -> configureVerifier(jwt)
577+
.withOrganization("org_123")
578+
.build()
579+
.verify(jwt),
479580
"Organization Id (org_id) claim must be a string present in the ID token");
480581
}
481582

482583
@Test
483-
public void failsWhenOrganizationExpectedButClaimIsNotString() {
584+
public void succeedsWhenOrganizationNameDoesNotMatchExpected_caseInsensitive() {
585+
String token = JWT.create()
586+
.withSubject("auth0|sdk458fks")
587+
.withAudience(AUDIENCE)
588+
.withIssuedAt(getYesterday())
589+
.withExpiresAt(getTomorrow())
590+
.withIssuer("https://" + DOMAIN + "/")
591+
.withClaim("org_name", "my org")
592+
.sign(Algorithm.HMAC256("secret"));
593+
594+
String jwt = JWT.decode(token).getToken();
595+
596+
configureVerifier(jwt)
597+
.withOrganization("My org")
598+
.build()
599+
.verify(jwt);
600+
}
601+
602+
@Test
603+
public void failsWhenOrganizationIdExpectedButClaimIsNotString() {
484604
String token = JWT.create()
485605
.withSubject("auth0|sdk458fks")
486606
.withAudience(AUDIENCE)
@@ -497,12 +617,12 @@ public void failsWhenOrganizationExpectedButClaimIsNotString() {
497617
.withOrganization("org_123")
498618
.build()
499619
.verify(jwt);
500-
},
620+
},
501621
"Organization Id (org_id) claim must be a string present in the ID token");
502622
}
503623

504624
@Test
505-
public void succeedsWhenOrganizationNotSpecifiedButIsPresent() {
625+
public void succeedsWhenOrganizationIdNotSpecifiedButIsPresent() {
506626
String token = JWT.create()
507627
.withSubject("auth0|sdk458fks")
508628
.withAudience(AUDIENCE)

0 commit comments

Comments
 (0)