Skip to content

Commit

Permalink
feat: add parseAccessToken() API
Browse files Browse the repository at this point in the history
  • Loading branch information
hsluoyz committed Feb 20, 2024
1 parent 368119e commit 8d1a6ea
Show file tree
Hide file tree
Showing 5 changed files with 161 additions and 9 deletions.
27 changes: 19 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,14 +37,14 @@ yarn add casdoor-js-sdk

Initialization requires 5 parameters, which are all string type:

| Name (in order) | Must | Description |
| ---------------- | ---- | --------------------------------------------------- |
| serverUrl | Yes | your Casdoor server URL |
| clientId | Yes | the Client ID of your Casdoor application |
| appName | Yes | the name of your Casdoor application |
| organizationName | Yes | the name of the Casdoor organization connected with your Casdoor application |
| redirectPath | No | the path of the redirect URL for your Casdoor application, will be `/callback` if not provided |
| signinPath | No | the path of the signin URL for your Casdoor application, will be `/api/signin` if not provided |
| Name (in order) | Must | Description |
|------------------|------|------------------------------------------------------------------------------------------------|
| serverUrl | Yes | your Casdoor server URL |
| clientId | Yes | the Client ID of your Casdoor application |
| appName | Yes | the name of your Casdoor application |
| organizationName | Yes | the name of the Casdoor organization connected with your Casdoor application |
| redirectPath | No | the path of the redirect URL for your Casdoor application, will be `/callback` if not provided |
| signinPath | No | the path of the signin URL for your Casdoor application, will be `/api/signin` if not provided |

```typescript
import {SDK, SdkConfig} from 'casdoor-js-sdk'
Expand Down Expand Up @@ -198,6 +198,17 @@ sdk.exchangeForAccessToken(additionalParams).then((resp) => {
});
```

#### Parse the access token

Once you have an access token, you can parse it into JWT header and payload.

```typescript
const result = sdk.parseAccessToken(accessToken);
console.log("JWT algorithm: " + result.header.alg);
console.log("User organization: " + result.payload.owner);
console.log("User name: " + result.payload.name);
```

#### Get user info

Once you have an access token, you can use it to get user info.
Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@
},
"homepage": "https://github.com/casdoor/casdoor-js-sdk",
"dependencies": {
"js-pkce": "^1.3.0"
"js-pkce": "^1.3.0",
"jwt-decode": "^4.0.0"
}
}
120 changes: 120 additions & 0 deletions src/sdk.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import PKCE from 'js-pkce';
import ITokenResponse from "js-pkce/dist/ITokenResponse";
import IObject from "js-pkce/dist/IObject";
import {jwtDecode, JwtHeader} from "jwt-decode";

export interface SdkConfig {
serverUrl: string, // your Casdoor server URL, e.g., "https://door.casbin.com" for the official demo site
Expand Down Expand Up @@ -44,6 +45,115 @@ export interface Account {
accessToken: string
}

export interface JwtPayload {
owner: string;
name: string;
createdTime: string;
updatedTime: string;
deletedTime: string;
id: string;
type: string;
password: string;
passwordSalt: string;
passwordType: string;
displayName: string;
firstName: string;
lastName: string;
avatar: string;
avatarType: string;
permanentAvatar: string;
email: string;
emailVerified: boolean;
phone: string;
countryCode: string;
region: string;
location: string;
address: string[];
affiliation: string;
title: string;
idCardType: string;
idCard: string;
homepage: string;
bio: string;
language: string;
gender: string;
birthday: string;
education: string;
score: number;
karma: number;
ranking: number;
isDefaultAvatar: boolean;
isOnline: boolean;
isAdmin: boolean;
isForbidden: boolean;
isDeleted: boolean;
signupApplication: string;
hash: string;
preHash: string;
accessKey: string;
accessSecret: string;
github: string;
google: string;
qq: string;
wechat: string;
facebook: string;
dingtalk: string;
weibo: string;
gitee: string;
linkedin: string;
wecom: string;
lark: string;
gitlab: string;
createdIp: string;
lastSigninTime: string;
lastSigninIp: string;
preferredMfaType: string;
recoveryCodes: null | string[];
totpSecret: string;
mfaPhoneEnabled: boolean;
mfaEmailEnabled: boolean;
ldap: string;
properties: Record<string, unknown>;
roles: string[];
permissions: Permission[];
groups: string[];
lastSigninWrongTime: string;
signinWrongTimes: number;
tokenType: string;
tag: string;
scope: string;
iss: string;
sub: string;
aud: string[];
exp: number;
nbf: number;
iat: number;
jti: string;
}

export interface Permission {
owner: string;
name: string;
createdTime: string;
displayName: string;
description: string;
users: string[] | null;
groups: string[];
roles: string[];
domains: string[];
model: string;
adapter: string;
resourceType: string;
resources: string[];
actions: string[];
effect: string;
isEnabled: boolean;
submitter: string;
approver: string;
approveTime: string;
state: string;
}

class Sdk {
private config: SdkConfig
private pkce: PKCE
Expand Down Expand Up @@ -221,6 +331,16 @@ class Sdk {
}).then(res => res.json()
);
}

public parseAccessToken(accessToken: string): { header: JwtHeader, payload: JwtPayload } {
try {
const parsedHeader: JwtHeader = jwtDecode<JwtHeader>(accessToken, { header: true });
const parsedPayload: JwtPayload = jwtDecode<JwtPayload>(accessToken);
return { header: parsedHeader, payload: parsedPayload };
} catch (error: any) {
throw new Error(error.message);
}
}
}

export default Sdk;
15 changes: 15 additions & 0 deletions test/sdk.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,3 +87,18 @@ describe('getSigninUrl', () => {
expect(url).toContain(`state=${state}`);
});
});

describe('parseAccessToken', () => {
it('should correctly parse JWT token', () => {
const sdk = new Sdk(sdkConfig);

const accessToken = 'eyJhbGciOiJSUzI1NiIsImtpZCI6ImNlcnQtYnVpbHQtaW4iLCJ0eXAiOiJKV1QifQ.eyJvd25lciI6ImNhc2JpbiIsIm5hbWUiOiJhZG1pbiIsImNyZWF0ZWRUaW1lIjoiMjAyMC0wNy0xNlQyMTo0Njo1MiswODowMCIsInVwZGF0ZWRUaW1lIjoiMjAyNC0wMi0yMFQxMzo1MzoyNSswODowMCIsImRlbGV0ZWRUaW1lIjoiIiwiaWQiOiI5ZWIyMGY3OS0zYmI1LTRlNzQtOTlhYy0zOWUzYjlhMTcxZTgiLCJ0eXBlIjoibm9ybWFsLXVzZXIiLCJwYXNzd29yZCI6IiIsInBhc3N3b3JkU2FsdCI6IiIsInBhc3N3b3JkVHlwZSI6InBsYWluIiwiZGlzcGxheU5hbWUiOiJIZXJtYW5uIiwiZmlyc3ROYW1lIjoiIiwibGFzdE5hbWUiOiIiLCJhdmF0YXIiOiJodHRwczovL2Nkbi5jYXNiaW4uY29tL2Nhc2Rvb3IvYXZhdGFyL2Nhc2Jpbi9hZG1pbi5wbmc_dD0xNjk0MjU3ODU5ODUwOTAwMjAwIiwiYXZhdGFyVHlwZSI6IiIsInBlcm1hbmVudEF2YXRhciI6Imh0dHBzOi8vY2RuLmNhc2Jpbi5jb20vY2FzZG9vci9hdmF0YXIvY2FzYmluL2FkbWluLnBuZyIsImVtYWlsIjoiYWRtaW5AY2FzYmluLm9yZyIsImVtYWlsVmVyaWZpZWQiOmZhbHNlLCJwaG9uZSI6IiIsImNvdW50cnlDb2RlIjoiIiwicmVnaW9uIjoiVVMiLCJsb2NhdGlvbiI6IlNKQyIsImFkZHJlc3MiOltdLCJhZmZpbGlhdGlvbiI6IiIsInRpdGxlIjoiIiwiaWRDYXJkVHlwZSI6IiIsImlkQ2FyZCI6IiIsImhvbWVwYWdlIjoiIiwiYmlvIjoi5b-D54y_5LiN5a6a77yM5oSP6ams5Zub6amw77yM57qi5YyFIiwibGFuZ3VhZ2UiOiIiLCJnZW5kZXIiOiIiLCJiaXJ0aGRheSI6IiIsImVkdWNhdGlvbiI6IiIsInNjb3JlIjo5ODgyLCJrYXJtYSI6MTYwLCJyYW5raW5nIjoxMCwiaXNEZWZhdWx0QXZhdGFyIjpmYWxzZSwiaXNPbmxpbmUiOnRydWUsImlzQWRtaW4iOnRydWUsImlzRm9yYmlkZGVuIjpmYWxzZSwiaXNEZWxldGVkIjpmYWxzZSwic2lnbnVwQXBwbGljYXRpb24iOiJhcHAtY2Fzbm9kZSIsImhhc2giOiIiLCJwcmVIYXNoIjoiIiwiYWNjZXNzS2V5IjoiIiwiYWNjZXNzU2VjcmV0IjoiIiwiZ2l0aHViIjoiIiwiZ29vZ2xlIjoiIiwicXEiOiIiLCJ3ZWNoYXQiOiJveFc5TzFSMXdHbS1uZU9OcDNOU1JXM0ppVm5RIiwiZmFjZWJvb2siOiIiLCJkaW5ndGFsayI6IiIsIndlaWJvIjoiIiwiZ2l0ZWUiOiIiLCJsaW5rZWRpbiI6IiIsIndlY29tIjoiIiwibGFyayI6IiIsImdpdGxhYiI6IiIsImNyZWF0ZWRJcCI6IiIsImxhc3RTaWduaW5UaW1lIjoiIiwibGFzdFNpZ25pbklwIjoiIiwicHJlZmVycmVkTWZhVHlwZSI6IiIsInJlY292ZXJ5Q29kZXMiOm51bGwsInRvdHBTZWNyZXQiOiIiLCJtZmFQaG9uZUVuYWJsZWQiOmZhbHNlLCJtZmFFbWFpbEVuYWJsZWQiOmZhbHNlLCJsZGFwIjoiIiwicHJvcGVydGllcyI6eyJiaW8iOiIiLCJjaGVja2luRGF0ZSI6IjIwMjQwMjAzIiwiZWRpdG9yVHlwZSI6InJpY2h0ZXh0IiwiZW1haWxWZXJpZmllZFRpbWUiOiIyMDIwLTA3LTE2VDIxOjQ2OjUyKzA4OjAwIiwiZmlsZVF1b3RhIjoiNTAiLCJsYXN0QWN0aW9uRGF0ZSI6IjIwMjQtMDItMjBUMTM6NTM6MjUrMDg6MDAiLCJsb2NhdGlvbiI6IiIsIm5vIjoiMjIiLCJvYXV0aF9RUV9kaXNwbGF5TmFtZSI6IiIsIm9hdXRoX1FRX3ZlcmlmaWVkVGltZSI6IiIsIm9hdXRoX1dlQ2hhdF9hdmF0YXJVcmwiOiJodHRwczovL3RoaXJkd3gucWxvZ28uY24vbW1vcGVuL3ZpXzMyL1EwajRUd0dUZlRJUXowTWljanY3dzd4ZXUyVW5XMWRoZ0xPUHZaYkxJSmlieExLVTU2WURMcDQ3eVZROVl6dUVqMW5tYWRjYkprTnB3eWliNVd6MWZRTkp3LzEzMiIsIm9hdXRoX1dlQ2hhdF9kaXNwbGF5TmFtZSI6ImNhcm1lbiIsIm9hdXRoX1dlQ2hhdF9pZCI6Im94VzlPMVIxd0dtLW5lT05wM05TUlczSmlWblEiLCJvYXV0aF9XZUNoYXRfdXNlcm5hbWUiOiJjYXJtZW4iLCJvbmxpbmVTdGF0dXMiOiJmYWxzZSIsInBob25lVmVyaWZpZWRUaW1lIjoiIiwicmVuYW1lUXVvdGEiOiIzIiwidGFnbGluZSI6IiIsIndlYnNpdGUiOiIifSwicm9sZXMiOltdLCJwZXJtaXNzaW9ucyI6W3sib3duZXIiOiJjYXNiaW4iLCJuYW1lIjoicGVybWlzc2lvbi1jYXNpYmFzZS1hZG1pbiIsImNyZWF0ZWRUaW1lIjoiMjAyMy0wNi0yM1QwMToxNTowOSswODowMCIsImRpc3BsYXlOYW1lIjoiQ2FzaWJhc2UgQWRtaW4gUGVybWlzc2lvbiIsImRlc2NyaXB0aW9uIjoiIiwidXNlcnMiOm51bGwsImdyb3VwcyI6W10sInJvbGVzIjpbXSwiZG9tYWlucyI6WyJkZWZhdWx0Il0sIm1vZGVsIjoiRGVmYXVsdCIsImFkYXB0ZXIiOiIiLCJyZXNvdXJjZVR5cGUiOiJUcmVlTm9kZSIsInJlc291cmNlcyI6WyIvIl0sImFjdGlvbnMiOlsiQWRtaW4iXSwiZWZmZWN0IjoiQWxsb3ciLCJpc0VuYWJsZWQiOnRydWUsInN1Ym1pdHRlciI6ImFkbWluIiwiYXBwcm92ZXIiOiJhZG1pbiIsImFwcHJvdmVUaW1lIjoiMjAyMy0wNi0yM1QwMToxNTowOSswODowMCIsInN0YXRlIjoiQXBwcm92ZWQifV0sImdyb3VwcyI6W10sImxhc3RTaWduaW5Xcm9uZ1RpbWUiOiIyMDIzLTA4LTA4VDE4OjExOjA4WiIsInNpZ25pbldyb25nVGltZXMiOjAsInRva2VuVHlwZSI6ImFjY2Vzcy10b2tlbiIsInRhZyI6Ium5hem5hem5he-8jOabsumhueWQkeWkqeatjCIsInNjb3BlIjoicmVhZCIsImlzcyI6Imh0dHBzOi8vZG9vci5jYXNkb29yLmNvbSIsInN1YiI6IjllYjIwZjc5LTNiYjUtNGU3NC05OWFjLTM5ZTNiOWExNzFlOCIsImF1ZCI6WyIwYmE1MjgxMjFlYTg3YjNlYjU0ZCJdLCJleHAiOjE3MDkwMjk2OTcsIm5iZiI6MTcwODQyNDg5NywiaWF0IjoxNzA4NDI0ODk3LCJqdGkiOiJhZG1pbi9kZmUzM2Y0Ny04NGRjLTQxZjktOWE4OC03ZTU0ZWEzZTY5MjEifQ.f4l-lys7e34QEih4tJR0v5JpbIg1I8ljFoOnDnTe141UJ_ux9k2WqqCCw5g3EqwHLpiSgf_Q3ut7hgL-Ga911fLzJhSWDxx5nLfoKlQUaEu8mtz8MdleVCCytxAMxzJkeXcA7ng_QcXIFfKTRp6v5nUo8bVCp8nFfP9DJUD4irhaEwZqzJ6Y6xZRkn1YZht0j2ey39trn3cjWozKvNQNc-nSEik0UlPUO-VnQi8GnEy19C8rT6YltbboOYbmk7x57vOwecDhfUYoNdlseB3Ac3TXAHGVeCLyZWnLzU8JHNClzqqI-pUXKfQ5OGTkEBG8J2CKuzTG9cgHyAk5pA-B8Ea38rP5CNiUCbsaLR5o8bs0krJ9UJx-b52W4n8pSJmUUiE4qDCe_piesLERrTnQszFT_pG6aF_o5w0UN5Mr0houkDsqwj2sNa4oTtvkz1JuYGn1fqQ89jvPp9bGemyuI-N_gCjRecn7TKW-_1MrOYExboGCUsftY8K42PYtrpXY3hCLWx2IamMrU8fSbAqkBZym02EHEKoroCw269ejtL93ZhC6-eyljLl_Fb5NjF9infGxCRjaFco5M6k_ELKwnA5V65-OmTpT6Ti3ws6zhfs27ClZbFdtUB-HcYSMGNrqZbFdmH7ne1sKinwFsH51JAKSCCXyJOZsHMQ-RmugOAA';
const result = sdk.parseAccessToken(accessToken);

expect(result.header.alg).toEqual("RS256");
expect(result.header.kid).toEqual("cert-built-in");
expect(result.header.typ).toEqual("JWT");
expect(result.payload.owner).toEqual("casbin");
expect(result.payload.name).toEqual("admin");
});
});
5 changes: 5 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -4204,6 +4204,11 @@ just-diff@^5.0.1:
resolved "https://registry.yarnpkg.com/just-diff/-/just-diff-5.2.0.tgz#60dca55891cf24cd4a094e33504660692348a241"
integrity sha512-6ufhP9SHjb7jibNFrNxyFZ6od3g+An6Ai9mhGRvcYe8UJlH0prseN64M+6ZBBUoKYHZsitDP42gAJ8+eVWr3lw==

jwt-decode@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/jwt-decode/-/jwt-decode-4.0.0.tgz#2270352425fd413785b2faf11f6e755c5151bd4b"
integrity sha512-+KJGIyHgkGuIq3IEBNftfhW/LfWhXUIY6OmyVWjliu5KH1y0fw7VQ8YndE2O4qZdMSd9SqbnC8GOcZEy0Om7sA==

kind-of@^6.0.3:
version "6.0.3"
resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd"
Expand Down

0 comments on commit 8d1a6ea

Please sign in to comment.