From fe8975b6e28b4bb7d6094171d1d9f89b1356426a Mon Sep 17 00:00:00 2001 From: gyaneshgouraw-okta Date: Tue, 9 Jul 2024 18:38:46 +0530 Subject: [PATCH] Added support for Session & Refresh token in management api client --- src/management/__generated/index.ts | 4 + src/management/__generated/managers/index.ts | 2 + .../managers/refresh-tokens-manager.ts | 66 +++++ .../__generated/managers/sessions-manager.ts | 60 +++++ src/management/__generated/models/index.ts | 253 ++++++++++++++++++ test/management/refresh-tokens.test.ts | 140 ++++++++++ test/management/sessions.test.ts | 140 ++++++++++ 7 files changed, 665 insertions(+) create mode 100644 src/management/__generated/managers/refresh-tokens-manager.ts create mode 100644 src/management/__generated/managers/sessions-manager.ts create mode 100644 test/management/refresh-tokens.test.ts create mode 100644 test/management/sessions.test.ts diff --git a/src/management/__generated/index.ts b/src/management/__generated/index.ts index 298e0d5b6..2fc3f6bc6 100644 --- a/src/management/__generated/index.ts +++ b/src/management/__generated/index.ts @@ -23,10 +23,12 @@ import { LogsManager, OrganizationsManager, PromptsManager, + RefreshTokensManager, ResourceServersManager, RolesManager, RulesManager, RulesConfigsManager, + SessionsManager, StatsManager, TenantsManager, TicketsManager, @@ -59,10 +61,12 @@ export abstract class ManagementClientBase { public readonly logs = new LogsManager(this.configuration); public readonly organizations = new OrganizationsManager(this.configuration); public readonly prompts = new PromptsManager(this.configuration); + public readonly refreshTokens = new RefreshTokensManager(this.configuration); public readonly resourceServers = new ResourceServersManager(this.configuration); public readonly roles = new RolesManager(this.configuration); public readonly rules = new RulesManager(this.configuration); public readonly rulesConfigs = new RulesConfigsManager(this.configuration); + public readonly sessions = new SessionsManager(this.configuration); public readonly stats = new StatsManager(this.configuration); public readonly tenants = new TenantsManager(this.configuration); public readonly tickets = new TicketsManager(this.configuration); diff --git a/src/management/__generated/managers/index.ts b/src/management/__generated/managers/index.ts index 72ad5a671..465cfca91 100644 --- a/src/management/__generated/managers/index.ts +++ b/src/management/__generated/managers/index.ts @@ -19,10 +19,12 @@ export * from './log-streams-manager.js'; export * from './logs-manager.js'; export * from './organizations-manager.js'; export * from './prompts-manager.js'; +export * from './refresh-tokens-manager.js'; export * from './resource-servers-manager.js'; export * from './roles-manager.js'; export * from './rules-manager.js'; export * from './rules-configs-manager.js'; +export * from './sessions-manager.js'; export * from './stats-manager.js'; export * from './tenants-manager.js'; export * from './tickets-manager.js'; diff --git a/src/management/__generated/managers/refresh-tokens-manager.ts b/src/management/__generated/managers/refresh-tokens-manager.ts new file mode 100644 index 000000000..aef2ecc9e --- /dev/null +++ b/src/management/__generated/managers/refresh-tokens-manager.ts @@ -0,0 +1,66 @@ +import * as runtime from '../../../lib/runtime.js'; +import type { InitOverride, ApiResponse } from '../../../lib/runtime.js'; +import type { + GetRefreshToken200Response, + DeleteRefreshTokenRequest, + GetRefreshTokenRequest, +} from '../models/index.js'; + +const { BaseAPI } = runtime; + +/** + * + */ +export class RefreshTokensManager extends BaseAPI { + /** + * Delete a refresh token by its ID. + * Delete a refresh tokens + * + * @throws {RequiredError} + */ + async delete( + requestParameters: DeleteRefreshTokenRequest, + initOverrides?: InitOverride + ): Promise> { + runtime.validateRequiredRequestParams(requestParameters, ['id']); + + const response = await this.request( + { + path: `/refresh-tokens/{id}`.replace( + '{id}', + encodeURIComponent(String(requestParameters.id)) + ), + method: 'DELETE', + }, + initOverrides + ); + + return runtime.VoidApiResponse.fromResponse(response); + } + + /** + * Retrieve refresh token information. + * Get a refresh token + * + * @throws {RequiredError} + */ + async get( + requestParameters: GetRefreshTokenRequest, + initOverrides?: InitOverride + ): Promise> { + runtime.validateRequiredRequestParams(requestParameters, ['id']); + + const response = await this.request( + { + path: `/refresh-tokens/{id}`.replace( + '{id}', + encodeURIComponent(String(requestParameters.id)) + ), + method: 'GET', + }, + initOverrides + ); + + return runtime.JSONApiResponse.fromResponse(response); + } +} diff --git a/src/management/__generated/managers/sessions-manager.ts b/src/management/__generated/managers/sessions-manager.ts new file mode 100644 index 000000000..462b3e2b8 --- /dev/null +++ b/src/management/__generated/managers/sessions-manager.ts @@ -0,0 +1,60 @@ +import * as runtime from '../../../lib/runtime.js'; +import type { InitOverride, ApiResponse } from '../../../lib/runtime.js'; +import type { + GetSession200Response, + DeleteSessionRequest, + GetSessionRequest, +} from '../models/index.js'; + +const { BaseAPI } = runtime; + +/** + * + */ +export class SessionsManager extends BaseAPI { + /** + * Delete a session by ID. + * Delete session + * + * @throws {RequiredError} + */ + async delete( + requestParameters: DeleteSessionRequest, + initOverrides?: InitOverride + ): Promise> { + runtime.validateRequiredRequestParams(requestParameters, ['id']); + + const response = await this.request( + { + path: `/sessions/{id}`.replace('{id}', encodeURIComponent(String(requestParameters.id))), + method: 'DELETE', + }, + initOverrides + ); + + return runtime.VoidApiResponse.fromResponse(response); + } + + /** + * Retrieve session information. + * Get session + * + * @throws {RequiredError} + */ + async get( + requestParameters: GetSessionRequest, + initOverrides?: InitOverride + ): Promise> { + runtime.validateRequiredRequestParams(requestParameters, ['id']); + + const response = await this.request( + { + path: `/sessions/{id}`.replace('{id}', encodeURIComponent(String(requestParameters.id))), + method: 'GET', + }, + initOverrides + ); + + return runtime.JSONApiResponse.fromResponse(response); + } +} diff --git a/src/management/__generated/models/index.ts b/src/management/__generated/models/index.ts index 58f8adac0..d53eacd0d 100644 --- a/src/management/__generated/models/index.ts +++ b/src/management/__generated/models/index.ts @@ -6271,6 +6271,79 @@ export const GetPnProviders200ResponseProviderEnum = { export type GetPnProviders200ResponseProviderEnum = (typeof GetPnProviders200ResponseProviderEnum)[keyof typeof GetPnProviders200ResponseProviderEnum]; +/** + * + */ +export interface GetRefreshToken200Response { + [key: string]: any | any; + /** + * The ID of the refresh token + * + */ + id: string; + /** + * ID of the user which can be used when interacting with other APIs. + * + */ + user_id: string; + /** + */ + created_at: GetRefreshToken200ResponseCreatedAt | null; + /** + */ + idle_expires_at: GetRefreshToken200ResponseIdleExpiresAt | null; + /** + */ + expires_at: GetRefreshToken200ResponseExpiresAt | null; + /** + * ID of the client application granted with this refresh token + * + */ + client_id: string; + /** + * ID of the authenticated session used to obtain this refresh-token + * + */ + session_id: string | null; + /** + * True if the token is a rotating refresh token + * + */ + rotating: boolean; + /** + * A list of the resource server IDs associated to this refresh-token and their granted scopes + * + */ + resource_servers: Array; +} +/** + * + */ +export type GetRefreshToken200ResponseCreatedAt = string | { [key: string]: any }; +/** + * + */ +export type GetRefreshToken200ResponseExpiresAt = string | { [key: string]: any }; +/** + * + */ +export type GetRefreshToken200ResponseIdleExpiresAt = string | { [key: string]: any }; +/** + * + */ +export interface GetRefreshToken200ResponseResourceServersInner { + [key: string]: any | any; + /** + * Resource server ID + * + */ + audience: string; + /** + * List of scopes for the refresh token + * + */ + scopes: string; +} /** * */ @@ -6499,6 +6572,146 @@ export interface GetScimTokens200ResponseInner { */ last_used_at: string; } +/** + * + */ +export interface GetSession200Response { + [key: string]: any | any; + /** + * The ID of the session + * + */ + id: string; + /** + * ID of the user which can be used when interacting with other APIs. + * + */ + user_id: string; + /** + */ + created_at: GetSession200ResponseCreatedAt | null; + /** + */ + updated_at: GetSession200ResponseUpdatedAt | null; + /** + */ + authenticated_at: GetSession200ResponseAuthenticatedAt | null; + /** + */ + idle_expires_at: GetSession200ResponseIdleExpiresAt | null; + /** + */ + expires_at: GetSession200ResponseExpiresAt | null; + /** + */ + device: GetSession200ResponseDevice; + /** + * List of client details for the session + * + */ + clients: Array; + /** + */ + authentication: GetSession200ResponseAuthentication; +} +/** + * + */ +export type GetSession200ResponseAuthenticatedAt = string | { [key: string]: any }; +/** + * Details about authentication signals obtained during the login flow + */ +export interface GetSession200ResponseAuthentication { + [key: string]: any | any; + /** + * Contains the authentication methods a user has completed during their session + * + */ + methods: Array; +} +/** + * Authentication signal details + */ +export interface GetSession200ResponseAuthenticationMethodsInner { + [key: string]: any | any; + /** + * One of: "federated", "passkey", "pwd", "sms", "email", "mfa", "mock" or a custom method denoted by a URL + * + */ + name: string; + /** + */ + timestamp: GetSession200ResponseAuthenticationMethodsInnerTimestamp | null; + /** + * A specific MFA factor. Only present when "name" is set to "mfa" + * + */ + type$: string; +} +/** + * + */ +export type GetSession200ResponseAuthenticationMethodsInnerTimestamp = + | string + | { [key: string]: any }; +/** + * Client details + */ +export interface GetSession200ResponseClientsInner { + [key: string]: any | any; + /** + * ID of client for the session + * + */ + client_id: string; +} +/** + * + */ +export type GetSession200ResponseCreatedAt = string | { [key: string]: any }; +/** + * Metadata related to the device used in the session + */ +export interface GetSession200ResponseDevice { + [key: string]: any | any; + /** + * First IP address associated with this session + * + */ + initial_ip: string | null; + /** + * First autonomous system number associated with this session + * + */ + initial_asn: string; + /** + * Last user agent of the device from which this user logged in + * + */ + last_user_agent: string; + /** + * Last IP address from which this user logged in + * + */ + last_ip: string | null; + /** + * Last autonomous system number from which this user logged in + * + */ + last_asn: string; +} +/** + * + */ +export type GetSession200ResponseExpiresAt = string | { [key: string]: any }; +/** + * + */ +export type GetSession200ResponseIdleExpiresAt = string | { [key: string]: any }; +/** + * + */ +export type GetSession200ResponseUpdatedAt = string | { [key: string]: any }; /** * */ @@ -14227,6 +14440,26 @@ export interface PutPartialsRequest { */ prompt: PutPartialsPromptEnum; } +/** + * + */ +export interface DeleteRefreshTokenRequest { + /** + * ID of the refresh token to delete. + * + */ + id: string; +} +/** + * + */ +export interface GetRefreshTokenRequest { + /** + * ID refresh token to retrieve + * + */ + id: string; +} /** * */ @@ -14527,6 +14760,26 @@ export interface PutRulesConfigsByKeyOperationRequest { */ key: string; } +/** + * + */ +export interface DeleteSessionRequest { + /** + * ID of the session to delete. + * + */ + id: string; +} +/** + * + */ +export interface GetSessionRequest { + /** + * ID of session to retrieve + * + */ + id: string; +} /** * */ diff --git a/test/management/refresh-tokens.test.ts b/test/management/refresh-tokens.test.ts new file mode 100644 index 000000000..754691a6b --- /dev/null +++ b/test/management/refresh-tokens.test.ts @@ -0,0 +1,140 @@ +import nock from 'nock'; + +const API_URL = 'https://tenant.auth0.com/api/v2'; + +import { RefreshTokensManager, ManagementClient } from '../../src/index.js'; + +describe('RefreshTokensManager', () => { + let refreshTokens: RefreshTokensManager; + const token = 'TOKEN'; + + beforeAll(() => { + const client = new ManagementClient({ + domain: 'tenant.auth0.com', + token: token, + }); + refreshTokens = client.refreshTokens; + }); + + describe('#constructor', () => { + it('should throw an error when no base URL is provided', () => { + expect(() => { + new RefreshTokensManager({} as any); + }).toThrowError(Error); + }); + + it('should throw an error when the base URL is invalid', () => { + expect(() => { + new RefreshTokensManager({ baseUrl: '' } as any); + }).toThrowError(Error); + }); + }); + + describe('#get', () => { + let request: nock.Scope; + const id = '1'; + + beforeEach(() => { + request = nock(API_URL).get(`/refresh-tokens/${id}`).reply(200, {}); + }); + + it('should return a promise if no callback is given', (done) => { + refreshTokens.get({ id }).then(done.bind(null, null)).catch(done.bind(null, null)); + }); + + it('should pass any errors to the promise catch handler', (done) => { + nock.cleanAll(); + + nock(API_URL).get(`/refresh-tokens/${id}`).reply(500); + + refreshTokens.get({ id: id }).catch((err) => { + expect(err).toBeDefined(); + done(); + }); + }); + + it('should pass the body of the response to the "then" handler', (done) => { + nock.cleanAll(); + + const data = { id: '1' }; + nock(API_URL).get(`/refresh-tokens/${id}`).reply(200, data); + + refreshTokens.get({ id: id }).then((refreshToken) => { + expect(refreshToken.data.id).toBe(data.id); + + done(); + }); + }); + + it('should perform a GET request to /api/v2/refresh-tokens', (done) => { + refreshTokens.get({ id: id }).then(() => { + expect(request.isDone()).toBe(true); + + done(); + }); + }); + + it('should include the token in the Authorization header', (done) => { + nock.cleanAll(); + + const request = nock(API_URL) + .get(`/refresh-tokens/${id}`) + .matchHeader('Authorization', `Bearer ${token}`) + .reply(200, {}); + + refreshTokens.get({ id: id }).then(() => { + expect(request.isDone()).toBe(true); + done(); + }); + }); + }); + + describe('#delete', () => { + const id = '5'; + + let request: nock.Scope; + + beforeEach(() => { + request = nock(API_URL).delete(`/refresh-tokens/${id}`).reply(200, {}); + }); + + it('should return a promise when no callback is given', (done) => { + refreshTokens.delete({ id }).then(done.bind(null, null)); + }); + + it(`should perform a delete request to /refresh-tokens/${id}`, (done) => { + refreshTokens.delete({ id }).then(() => { + expect(request.isDone()).toBe(true); + + done(); + }); + }); + + it('should pass any errors to the promise catch handler', (done) => { + nock.cleanAll(); + + nock(API_URL).delete(`/refresh-tokens/${id}`).reply(500, {}); + + refreshTokens.delete({ id }).catch((err) => { + expect(err).toBeDefined(); + + done(); + }); + }); + + it('should include the token in the authorization header', (done) => { + nock.cleanAll(); + + const request = nock(API_URL) + .delete(`/refresh-tokens/${id}`) + .matchHeader('authorization', `Bearer ${token}`) + .reply(200, {}); + + refreshTokens.delete({ id }).then(() => { + expect(request.isDone()).toBe(true); + + done(); + }); + }); + }); +}); diff --git a/test/management/sessions.test.ts b/test/management/sessions.test.ts new file mode 100644 index 000000000..c11fd2434 --- /dev/null +++ b/test/management/sessions.test.ts @@ -0,0 +1,140 @@ +import nock from 'nock'; + +const API_URL = 'https://tenant.auth0.com/api/v2'; + +import { SessionsManager, ManagementClient } from '../../src/index.js'; + +describe('SessionsManager', () => { + let sessions: SessionsManager; + const token = 'TOKEN'; + + beforeAll(() => { + const client = new ManagementClient({ + domain: 'tenant.auth0.com', + token: token, + }); + sessions = client.sessions; + }); + + describe('#constructor', () => { + it('should throw an error when no base URL is provided', () => { + expect(() => { + new SessionsManager({} as any); + }).toThrowError(Error); + }); + + it('should throw an error when the base URL is invalid', () => { + expect(() => { + new SessionsManager({ baseUrl: '' } as any); + }).toThrowError(Error); + }); + }); + + describe('#get', () => { + let request: nock.Scope; + const id = '1'; + + beforeEach(() => { + request = nock(API_URL).get(`/sessions/${id}`).reply(200, {}); + }); + + it('should return a promise if no callback is given', (done) => { + sessions.get({ id }).then(done.bind(null, null)).catch(done.bind(null, null)); + }); + + it('should pass any errors to the promise catch handler', (done) => { + nock.cleanAll(); + + nock(API_URL).get(`/sessions/${id}`).reply(500); + + sessions.get({ id: id }).catch((err) => { + expect(err).toBeDefined(); + done(); + }); + }); + + it('should pass the body of the response to the "then" handler', (done) => { + nock.cleanAll(); + + const data = { id: '1' }; + nock(API_URL).get(`/sessions/${id}`).reply(200, data); + + sessions.get({ id: id }).then((session) => { + expect(session.data.id).toBe(data.id); + + done(); + }); + }); + + it('should perform a GET request to /api/v2/sessions', (done) => { + sessions.get({ id: id }).then(() => { + expect(request.isDone()).toBe(true); + + done(); + }); + }); + + it('should include the token in the Authorization header', (done) => { + nock.cleanAll(); + + const request = nock(API_URL) + .get(`/sessions/${id}`) + .matchHeader('Authorization', `Bearer ${token}`) + .reply(200, {}); + + sessions.get({ id: id }).then(() => { + expect(request.isDone()).toBe(true); + done(); + }); + }); + }); + + describe('#delete', () => { + const id = '5'; + + let request: nock.Scope; + + beforeEach(() => { + request = nock(API_URL).delete(`/sessions/${id}`).reply(200, {}); + }); + + it('should return a promise when no callback is given', (done) => { + sessions.delete({ id }).then(done.bind(null, null)); + }); + + it(`should perform a delete request to /sessions/${id}`, (done) => { + sessions.delete({ id }).then(() => { + expect(request.isDone()).toBe(true); + + done(); + }); + }); + + it('should pass any errors to the promise catch handler', (done) => { + nock.cleanAll(); + + nock(API_URL).delete(`/sessions/${id}`).reply(500, {}); + + sessions.delete({ id }).catch((err) => { + expect(err).toBeDefined(); + + done(); + }); + }); + + it('should include the token in the authorization header', (done) => { + nock.cleanAll(); + + const request = nock(API_URL) + .delete(`/sessions/${id}`) + .matchHeader('authorization', `Bearer ${token}`) + .reply(200, {}); + + sessions.delete({ id }).then(() => { + expect(request.isDone()).toBe(true); + + done(); + }); + }); + }); +});