-
Notifications
You must be signed in to change notification settings - Fork 351
feat(types,shared): JWT v2 - Support new organization claims structure #5549
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from 18 commits
Commits
Show all changes
20 commits
Select commit
Hold shift + click to select a range
392904d
feat(types): Organization structure for JWT v2
octoper d6dac37
feat(shared): Moved resolveSignedInAuthStateFromJWTClaims to shared p…
octoper 856edcd
refactor(shared,types): Rename claim to
octoper 502277a
refactor(shared): Replace if with a switch
octoper 7653b70
refactor(shared,backend,clerk-js): Add __experimental_ prefix
octoper 8a247df
chore(types,shared): Added tests and did some cleanup
octoper 2498d7c
chore(shared): Rename test case
octoper 057913c
chore(repo): Adds changeset
octoper 1a3c152
chore(shared,types): Org permissions claims is a string in v2
octoper 00935b4
refactor(clerk-js,shared,type): Support new claims and keep orgPermis…
octoper 79c00e1
chore(shared,types): Move SharedSignedInAuthObjectProperties to @cler…
octoper 7cc576a
fix(shared): Add org: prefix to org role
octoper ceab9e7
fix(shared): Add org: prefix to org roles to match previous behavior
octoper 9e968f8
chore(clerk-js): Change bundlewatch limit
octoper 1b59290
fix(shared): Only parse permissions if o.per and o.fpm are not undefined
octoper 1937de1
fix(shared): Only handle org claims if o is present
octoper cd352aa
chore(backend): Use SharedSignedInAuthObjectProperties for SignedInAu…
octoper f982c48
chore(repo): Update changeset
octoper 5f27918
chore(shared,types): Remove v from JWTPayloadBase as is not needed
octoper c1cb785
chore(clerk-js): Change bundlewatch limit
octoper File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
--- | ||
'@clerk/shared': minor | ||
'@clerk/types': minor | ||
--- | ||
|
||
Adding the new `o` claim that contains all organization related info for JWT v2 schema |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
--- | ||
'@clerk/clerk-js': patch | ||
'@clerk/backend': patch | ||
--- | ||
|
||
Uses the helper function `__experimental_JWTPayloadToAuthObjectProperties` from `@clerk/shared` to handle the new JWT v2 schema. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,166 @@ | ||
import { __experimental_JWTPayloadToAuthObjectProperties as JWTPayloadToAuthObjectProperties } from '../jwtPayloadParser'; | ||
|
||
const baseClaims = { | ||
exp: 1234567890, | ||
iat: 1234567890, | ||
iss: 'https://api.clerk.com', | ||
sub: 'sub', | ||
sid: 'sid', | ||
azp: 'azp', | ||
nbf: 1234567890, | ||
__raw: '', | ||
}; | ||
|
||
describe('JWTPayloadToAuthObjectProperties', () => { | ||
test('auth object with JWT v2 does not produces anything org related if there is no org active', () => { | ||
const { sessionClaims: v2Claims, ...signedInAuthObjectV2 } = JWTPayloadToAuthObjectProperties({ | ||
...baseClaims, | ||
v: 2, | ||
fea: 'u:impersonation,u:memberships', | ||
}); | ||
|
||
const { sessionClaims: v1Claims, ...signedInAuthObjectV1 } = JWTPayloadToAuthObjectProperties({ | ||
...baseClaims, | ||
}); | ||
expect(signedInAuthObjectV1).toEqual(signedInAuthObjectV2); | ||
expect(signedInAuthObjectV1.orgId).toBeUndefined(); | ||
expect(signedInAuthObjectV1.orgPermissions).toBeUndefined(); | ||
expect(signedInAuthObjectV1.orgRole).toBeUndefined(); | ||
expect(signedInAuthObjectV1.orgSlug).toBeUndefined(); | ||
}); | ||
|
||
test('produced auth object is the same for v1 and v2', () => { | ||
const { sessionClaims: v2Claims, ...signedInAuthObjectV2 } = JWTPayloadToAuthObjectProperties({ | ||
...baseClaims, | ||
v: 2, | ||
fea: 'o:impersonation', | ||
o: { | ||
id: 'org_xxxxxxx', | ||
rol: 'admin', | ||
slg: '/test', | ||
per: 'read,manage', | ||
fpm: '3', | ||
}, | ||
}); | ||
|
||
const { sessionClaims: v1Claims, ...signedInAuthObjectV1 } = JWTPayloadToAuthObjectProperties({ | ||
...baseClaims, | ||
org_id: 'org_xxxxxxx', | ||
org_role: 'org:admin', | ||
org_slug: '/test', | ||
org_permissions: ['org:impersonation:read', 'org:impersonation:manage'], | ||
}); | ||
expect(signedInAuthObjectV1).toEqual(signedInAuthObjectV2); | ||
}); | ||
|
||
test('produced auth object is the same for v1 and v2', () => { | ||
const { sessionClaims: v2Claims, ...signedInAuthObjectV2 } = JWTPayloadToAuthObjectProperties({ | ||
...baseClaims, | ||
v: 2, | ||
fea: 'o:impersonation', | ||
o: { | ||
id: 'org_xxxxxxx', | ||
rol: 'admin', | ||
slg: '/test', | ||
per: 'read,manage', | ||
fpm: '3', | ||
}, | ||
}); | ||
|
||
const { sessionClaims: v1Claims, ...signedInAuthObjectV1 } = JWTPayloadToAuthObjectProperties({ | ||
...baseClaims, | ||
org_id: 'org_xxxxxxx', | ||
org_role: 'org:admin', | ||
org_slug: '/test', | ||
org_permissions: ['org:impersonation:read', 'org:impersonation:manage'], | ||
}); | ||
expect(signedInAuthObjectV1).toEqual(signedInAuthObjectV2); | ||
}); | ||
|
||
test('org permissions are generated correctly when fea, per, and fpm are present', () => { | ||
const { sessionClaims: v2Claims, ...signedInAuthObject } = JWTPayloadToAuthObjectProperties({ | ||
...baseClaims, | ||
v: 2, | ||
fea: 'o:impersonation,o:memberships', | ||
o: { | ||
id: 'org_xxxxxxx', | ||
rol: 'admin', | ||
slg: '/test', | ||
per: 'read,manage', | ||
fpm: '2,3', | ||
}, | ||
}); | ||
|
||
expect(signedInAuthObject.orgPermissions?.sort()).toEqual( | ||
['org:impersonation:read', 'org:memberships:read', 'org:memberships:manage'].sort(), | ||
); | ||
}); | ||
|
||
test('if a feature is not mapped to any permissions it is added as is to the orgPermissions array', () => { | ||
const { sessionClaims: v2Claims, ...signedInAuthObject } = JWTPayloadToAuthObjectProperties({ | ||
...baseClaims, | ||
v: 2, | ||
fea: 'o:impersonation,o:memberships,o:feature3', | ||
o: { | ||
id: 'org_id', | ||
rol: 'admin', | ||
slg: 'org_slug', | ||
per: 'read,manage', | ||
fpm: '2,3', | ||
}, | ||
}); | ||
|
||
expect(signedInAuthObject.orgPermissions?.sort()).toEqual( | ||
['org:impersonation:read', 'org:memberships:read', 'org:memberships:manage'].sort(), | ||
); | ||
}); | ||
|
||
test('includes both org and user scoped features', () => { | ||
const { sessionClaims: v2Claims, ...signedInAuthObject } = JWTPayloadToAuthObjectProperties({ | ||
...baseClaims, | ||
v: 2, | ||
fea: 'uo:impersonation,o:memberships,uo:feature3', | ||
o: { | ||
id: 'org_id', | ||
rol: 'admin', | ||
slg: 'org_slug', | ||
per: 'read,manage', | ||
fpm: '2,3,2', | ||
}, | ||
}); | ||
|
||
expect(signedInAuthObject.orgPermissions?.sort()).toEqual( | ||
['org:impersonation:read', 'org:memberships:read', 'org:memberships:manage', 'org:feature3:read'].sort(), | ||
); | ||
}); | ||
|
||
test('if there is no o.fpm and o.per org permissions should be empty arrat', () => { | ||
const { sessionClaims: v2Claims, ...signedInAuthObject } = JWTPayloadToAuthObjectProperties({ | ||
...baseClaims, | ||
v: 2, | ||
fea: 'u:impersonation,u:memberships,u:feature3', | ||
o: { | ||
id: 'org_id', | ||
rol: 'admin', | ||
slg: 'org_slug', | ||
}, | ||
}); | ||
|
||
expect(signedInAuthObject.orgPermissions).toEqual([]); | ||
}); | ||
|
||
test('org role is prefixed with org:', () => { | ||
const { sessionClaims: v2Claims, ...signedInAuthObject } = JWTPayloadToAuthObjectProperties({ | ||
...baseClaims, | ||
v: 2, | ||
fea: 'u:impersonation,u:memberships,u:feature3', | ||
o: { | ||
id: 'org_id', | ||
rol: 'admin', | ||
slg: 'org_slug', | ||
}, | ||
}); | ||
|
||
expect(signedInAuthObject.orgRole).toBe('org:admin'); | ||
}); | ||
}); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.