Skip to content

Commit

Permalink
fix: authts#225 move revoke from TokenRevocationClient into TokenClient
Browse files Browse the repository at this point in the history
  • Loading branch information
pamapa committed Nov 30, 2021
1 parent dcde654 commit e4570ee
Show file tree
Hide file tree
Showing 8 changed files with 83 additions and 143 deletions.
19 changes: 2 additions & 17 deletions docs/oidc-client-ts.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@ export class MetadataService {
// (undocumented)
protected _getMetadataProperty(name: keyof OidcMetadata, optional?: boolean): Promise<string | boolean | string[] | undefined>;
// (undocumented)
getRevocationEndpoint(): Promise<string | undefined>;
getRevocationEndpoint(optional?: boolean): Promise<string | undefined>;
// (undocumented)
getSigningKeys(): Promise<SigningKey[] | null>;
// (undocumented)
Expand Down Expand Up @@ -699,15 +699,6 @@ export interface StateStore {
set(key: string, value: string): Promise<void>;
}

// @public (undocumented)
export class TokenRevocationClient {
constructor(settings: OidcClientSettingsStore, metadataService: MetadataService);
// (undocumented)
revoke(token: string, required: boolean, type?: string): Promise<void>;
// (undocumented)
protected _revoke(url: string, client_id: string, client_secret: string | undefined, token: string, type: string): Promise<void>;
}

// @public (undocumented)
export class User {
constructor(args: {
Expand Down Expand Up @@ -775,11 +766,7 @@ export class UserManager {
// (undocumented)
revokeAccessToken(): Promise<void>;
// (undocumented)
protected _revokeAccessTokenInternal(access_token: string, required: boolean): Promise<boolean>;
// (undocumented)
protected _revokeInternal(user: User | null, required?: boolean): Promise<boolean>;
// (undocumented)
protected _revokeRefreshTokenInternal(refresh_token: string | undefined, required: boolean): Promise<boolean>;
protected _revokeInternal(user: User | null, optional: boolean): Promise<boolean>;
// (undocumented)
protected readonly _sessionMonitor: SessionMonitor | null;
readonly settings: UserManagerSettingsStore;
Expand Down Expand Up @@ -826,8 +813,6 @@ export class UserManager {
// (undocumented)
protected readonly _tokenClient: TokenClient;
// (undocumented)
protected readonly _tokenRevocationClient: TokenRevocationClient;
// (undocumented)
protected _useRefreshToken(user: User): Promise<User>;
// (undocumented)
protected get _userStoreKey(): string;
Expand Down
18 changes: 10 additions & 8 deletions src/JsonService.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -233,7 +233,7 @@ describe("JsonService", () => {
Accept: "application/json",
"Content-Type": "application/json"
}),
json: () => Promise.resolve(json)
text: () => Promise.resolve(JSON.stringify(json))
} as Response);

// act
Expand Down Expand Up @@ -263,7 +263,7 @@ describe("JsonService", () => {
Accept: "application/json",
"Content-Type": "application/json"
}),
json: () => Promise.reject(error)
text: () => Promise.reject(error)
} as Response);

// act
Expand All @@ -282,7 +282,7 @@ describe("JsonService", () => {
Accept: "application/json",
"Content-Type": "text/html"
}),
json: () => Promise.resolve(json)
text: () => Promise.resolve(JSON.stringify(json))
} as Response);

// act
Expand All @@ -301,7 +301,7 @@ describe("JsonService", () => {
Accept: "application/json",
"Content-Type": "application/json"
}),
json: () => Promise.resolve(json)
text: () => Promise.resolve(JSON.stringify(json))
} as Response);

// act
Expand All @@ -320,7 +320,7 @@ describe("JsonService", () => {
Accept: "application/json",
"Content-Type": "application/json"
}),
json: () => Promise.resolve(json)
text: () => Promise.resolve(JSON.stringify(json))
} as Response);

// act
Expand All @@ -339,7 +339,7 @@ describe("JsonService", () => {
Accept: "application/json",
"Content-Type": "application/json"
}),
json: () => Promise.reject(new SyntaxError("Unexpected token a in JSON"))
text: () => Promise.resolve("not_json_data")
} as Response);

// act
Expand All @@ -358,7 +358,7 @@ describe("JsonService", () => {
Accept: "application/json",
"Content-Type": "text/html"
}),
json: () => Promise.resolve(json)
text: () => Promise.resolve(JSON.stringify(json))
} as Response);

// act
Expand All @@ -369,11 +369,13 @@ describe("JsonService", () => {

it("should reject promise when http response is not 200", async () => {
// arrange
const json = {};
mocked(fetch).mockResolvedValue({
status: 500,
statusText: "server error",
ok: false,
headers: new Headers(),
text: () => Promise.resolve(JSON.stringify(json))
} as Response);

// act
Expand All @@ -393,7 +395,7 @@ describe("JsonService", () => {
Accept: "application/json",
"Content-Type": "foo/bar"
}),
json: () => Promise.resolve(json)
text: () => Promise.resolve(JSON.stringify(json))
} as Response);

// act
Expand Down
9 changes: 7 additions & 2 deletions src/JsonService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,22 +99,27 @@ export class JsonService {
if (contentType && !this._contentTypes.find(item => contentType.startsWith(item))) {
throw new Error(`Invalid response Content-Type: ${(contentType ?? "undefined")}, from URL: ${url}`);
}
let json: Record<string, unknown>;

const responseText = await response.text();

let json: Record<string, unknown> = {};
try {
json = await response.json();
json = JSON.parse(responseText);
}
catch (err) {
this._logger.error("postForm: Error parsing JSON response", err);
if (response.ok) throw err;
throw new Error(`${response.statusText} (${response.status})`);
}

if (!response.ok) {
this._logger.error("postForm: Error from server:", json);
if (json.error) {
throw new ErrorResponse(json);
}
throw new Error(`${response.statusText} (${response.status}): ${JSON.stringify(json)}`);
}

return json;
}
}
4 changes: 2 additions & 2 deletions src/MetadataService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -100,8 +100,8 @@ export class MetadataService {
return this._getMetadataProperty("end_session_endpoint", true) as Promise<string | undefined>;
}

public getRevocationEndpoint(): Promise<string | undefined> {
return this._getMetadataProperty("revocation_endpoint", true) as Promise<string | undefined>;
public getRevocationEndpoint(optional = true): Promise<string | undefined> {
return this._getMetadataProperty("revocation_endpoint", optional) as Promise<string | undefined>;
}

public getKeysEndpoint(optional?: true): Promise<string | undefined>
Expand Down
42 changes: 42 additions & 0 deletions src/TokenClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,16 @@ export interface ExchangeRefreshTokenArgs {
refresh_token: string;
}

/**
* @internal
*/
export interface RevokeArgs {
token: string;
token_type_hint: "access_token" | "refresh_token";

optional?: boolean;
}

/**
* @internal
*/
Expand Down Expand Up @@ -148,4 +158,36 @@ export class TokenClient {

return response;
}

public async revoke({
optional = false,
...args
}: RevokeArgs): Promise<void> {
if (!args.token) {
this._logger.error("revoke: No token passed");
throw new Error("A token is required");
}

const url = await this._metadataService.getRevocationEndpoint(optional);
if (!url) {
// not required, so don't error and just return
return;
}

this._logger.debug("revoke: Received revocation endpoint, revoking " + args.token_type_hint);

const params = new URLSearchParams();
for (const [key, value] of Object.entries(args)) {
if (value != null) {
params.set(key, value);
}
}
params.set("client_id", this._settings.client_id);
if (this._settings.client_secret) {
params.set("client_secret", this._settings.client_secret);
}

await this._jsonService.postForm(url, params);
this._logger.debug("revoke: response received");
}
}
81 changes: 0 additions & 81 deletions src/TokenRevocationClient.ts

This file was deleted.

Loading

0 comments on commit e4570ee

Please sign in to comment.