@authorizerdev/authorizer-js 1.2.1 → 1.2.2-beta.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/index.ts DELETED
@@ -1,499 +0,0 @@
1
- // Note: write gql query in single line to reduce bundle size
2
- import crossFetch from 'cross-fetch'
3
- import { DEFAULT_AUTHORIZE_TIMEOUT_IN_SECONDS } from './constants'
4
- import * as Types from './types'
5
- import {
6
- bufferToBase64UrlEncoded,
7
- createQueryParams,
8
- createRandomString,
9
- encode,
10
- executeIframe,
11
- hasWindow,
12
- sha256,
13
- trimURL,
14
- } from './utils'
15
-
16
- // re-usable gql response fragment
17
- const userFragment = 'id email email_verified given_name family_name middle_name nickname preferred_username picture signup_methods gender birthdate phone_number phone_number_verified roles created_at updated_at is_multi_factor_auth_enabled '
18
- const authTokenFragment = `message access_token expires_in refresh_token id_token should_show_otp_screen user { ${userFragment} }`
19
-
20
- // set fetch based on window object. Cross fetch have issues with umd build
21
- const getFetcher = () => (hasWindow() ? window.fetch : crossFetch)
22
-
23
- export * from './types'
24
- export class Authorizer {
25
- // class variable
26
- config: Types.ConfigType
27
- codeVerifier: string
28
-
29
- // constructor
30
- constructor(config: Types.ConfigType) {
31
- if (!config)
32
- throw new Error('Configuration is required')
33
-
34
- this.config = config
35
- if (!config.authorizerURL && !config.authorizerURL.trim())
36
- throw new Error('Invalid authorizerURL')
37
-
38
- if (config.authorizerURL)
39
- this.config.authorizerURL = trimURL(config.authorizerURL)
40
-
41
- if (!config.redirectURL && !config.redirectURL.trim())
42
- throw new Error('Invalid redirectURL')
43
- else
44
- this.config.redirectURL = trimURL(config.redirectURL)
45
-
46
- this.config.extraHeaders = {
47
- ...(config.extraHeaders || {}),
48
- 'x-authorizer-url': this.config.authorizerURL,
49
- 'Content-Type': 'application/json',
50
- }
51
- this.config.clientID = config.clientID.trim()
52
- }
53
-
54
- authorize = async (data: Types.AuthorizeInput) => {
55
- if (!hasWindow())
56
- throw new Error('this feature is only supported in browser')
57
-
58
- const scopes = ['openid', 'profile', 'email']
59
- if (data.use_refresh_token)
60
- scopes.push('offline_access')
61
-
62
- const requestData: Record<string, string> = {
63
- redirect_uri: this.config.redirectURL,
64
- response_mode: data.response_mode || 'web_message',
65
- state: encode(createRandomString()),
66
- nonce: encode(createRandomString()),
67
- response_type: data.response_type,
68
- scope: scopes.join(' '),
69
- client_id: this.config.clientID,
70
- }
71
-
72
- if (data.response_type === Types.ResponseTypes.Code) {
73
- this.codeVerifier = createRandomString()
74
- const sha = await sha256(this.codeVerifier)
75
- const codeChallenge = bufferToBase64UrlEncoded(sha)
76
- requestData.code_challenge = codeChallenge
77
- }
78
-
79
- const authorizeURL = `${
80
- this.config.authorizerURL
81
- }/authorize?${createQueryParams(requestData)}`
82
-
83
- if (requestData.response_mode !== 'web_message') {
84
- window.location.replace(authorizeURL)
85
- return
86
- }
87
-
88
- try {
89
- const iframeRes = await executeIframe(
90
- authorizeURL,
91
- this.config.authorizerURL,
92
- DEFAULT_AUTHORIZE_TIMEOUT_IN_SECONDS,
93
- )
94
-
95
- if (data.response_type === Types.ResponseTypes.Code) {
96
- // get token and return it
97
- const token = await this.getToken({ code: iframeRes.code })
98
- return token
99
- }
100
-
101
- // this includes access_token, id_token & refresh_token(optionally)
102
- return iframeRes
103
- }
104
- catch (err) {
105
- if (err.error) {
106
- window.location.replace(
107
- `${this.config.authorizerURL}/app?state=${encode(
108
- JSON.stringify(this.config),
109
- )}&redirect_uri=${this.config.redirectURL}`,
110
- )
111
- }
112
-
113
- throw err
114
- }
115
- }
116
-
117
- browserLogin = async (): Promise<Types.AuthToken | void> => {
118
- try {
119
- const token = await this.getSession()
120
- return token
121
- }
122
- catch (err) {
123
- if (!hasWindow())
124
- throw new Error('browserLogin is only supported for browsers')
125
-
126
- window.location.replace(
127
- `${this.config.authorizerURL}/app?state=${encode(
128
- JSON.stringify(this.config),
129
- )}&redirect_uri=${this.config.redirectURL}`,
130
- )
131
- }
132
- }
133
-
134
- forgotPassword = async (
135
- data: Types.ForgotPasswordInput,
136
- ): Promise<Types.Response | void> => {
137
- if (!data.state)
138
- data.state = encode(createRandomString())
139
-
140
- if (!data.redirect_uri)
141
- data.redirect_uri = this.config.redirectURL
142
-
143
- try {
144
- const forgotPasswordRes = await this.graphqlQuery({
145
- query: 'mutation forgotPassword($data: ForgotPasswordInput!) { forgot_password(params: $data) { message } }',
146
- variables: {
147
- data,
148
- },
149
- })
150
- return forgotPasswordRes.forgot_password
151
- }
152
- catch (error) {
153
- throw new Error(error)
154
- }
155
- }
156
-
157
- getMetaData = async (): Promise<Types.MetaData | void> => {
158
- try {
159
- const res = await this.graphqlQuery({
160
- query: 'query { meta { version is_google_login_enabled is_facebook_login_enabled is_github_login_enabled is_linkedin_login_enabled is_apple_login_enabled is_twitter_login_enabled is_microsoft_login_enabled is_email_verification_enabled is_basic_authentication_enabled is_magic_link_login_enabled is_sign_up_enabled is_strong_password_enabled } }',
161
- })
162
-
163
- return res.meta
164
- }
165
- catch (err) {
166
- throw new Error(err)
167
- }
168
- }
169
-
170
- getProfile = async (headers?: Types.Headers): Promise<Types.User | void> => {
171
- try {
172
- const profileRes = await this.graphqlQuery({
173
- query: `query { profile { ${userFragment} } }`,
174
- headers,
175
- })
176
-
177
- return profileRes.profile
178
- }
179
- catch (error) {
180
- throw new Error(error)
181
- }
182
- }
183
-
184
- // this is used to verify / get session using cookie by default. If using nodejs pass authorization header
185
- getSession = async (
186
- headers?: Types.Headers,
187
- params?: Types.SessionQueryInput,
188
- ): Promise<Types.AuthToken> => {
189
- try {
190
- const res = await this.graphqlQuery({
191
- query: `query getSession($params: SessionQueryInput){session(params: $params) { ${authTokenFragment} } }`,
192
- headers,
193
- variables: {
194
- params,
195
- },
196
- })
197
- return res.session
198
- }
199
- catch (err) {
200
- throw new Error(err)
201
- }
202
- }
203
-
204
- getToken = async (
205
- data: Types.GetTokenInput,
206
- ): Promise<Types.GetTokenResponse> => {
207
- if (!data.grant_type)
208
- data.grant_type = 'authorization_code'
209
-
210
- if (data.grant_type === 'refresh_token' && !data.refresh_token)
211
- throw new Error('Invalid refresh_token')
212
-
213
- if (data.grant_type === 'authorization_code' && !this.codeVerifier)
214
- throw new Error('Invalid code verifier')
215
-
216
- const requestData = {
217
- client_id: this.config.clientID,
218
- code: data.code || '',
219
- code_verifier: this.codeVerifier || '',
220
- grant_type: data.grant_type || '',
221
- refresh_token: data.refresh_token || '',
222
- }
223
-
224
- try {
225
- const fetcher = getFetcher()
226
- const res = await fetcher(`${this.config.authorizerURL}/oauth/token`, {
227
- method: 'POST',
228
- body: JSON.stringify(requestData),
229
- headers: {
230
- ...this.config.extraHeaders,
231
- },
232
- credentials: 'include',
233
- })
234
-
235
- const json = await res.json()
236
- if (res.status >= 400)
237
- throw new Error(json)
238
-
239
- return json
240
- }
241
- catch (err) {
242
- throw new Error(err)
243
- }
244
- }
245
-
246
- // helper to execute graphql queries
247
- // takes in any query or mutation string as input
248
- graphqlQuery = async (data: Types.GraphqlQueryInput) => {
249
- const fetcher = getFetcher()
250
- const res = await fetcher(`${this.config.authorizerURL}/graphql`, {
251
- method: 'POST',
252
- body: JSON.stringify({
253
- query: data.query,
254
- variables: data.variables || {},
255
- }),
256
- headers: {
257
- ...this.config.extraHeaders,
258
- ...(data.headers || {}),
259
- },
260
- credentials: 'include',
261
- })
262
-
263
- const json = await res.json()
264
-
265
- if (json.errors && json.errors.length) {
266
- console.error(json.errors)
267
- throw new Error(json.errors[0].message)
268
- }
269
-
270
- return json.data
271
- }
272
-
273
- login = async (data: Types.LoginInput): Promise<Types.AuthToken | void> => {
274
- try {
275
- const res = await this.graphqlQuery({
276
- query: `
277
- mutation login($data: LoginInput!) { login(params: $data) { ${authTokenFragment}}}
278
- `,
279
- variables: { data },
280
- })
281
-
282
- return res.login
283
- }
284
- catch (err) {
285
- throw new Error(err)
286
- }
287
- }
288
-
289
- logout = async (headers?: Types.Headers): Promise<Types.Response | void> => {
290
- try {
291
- const res = await this.graphqlQuery({
292
- query: ' mutation { logout { message } } ',
293
- headers,
294
- })
295
- return res.logout
296
- }
297
- catch (err) {
298
- console.error(err)
299
- }
300
- }
301
-
302
- magicLinkLogin = async (
303
- data: Types.MagicLinkLoginInput,
304
- ): Promise<Types.Response> => {
305
- try {
306
- if (!data.state)
307
- data.state = encode(createRandomString())
308
-
309
- if (!data.redirect_uri)
310
- data.redirect_uri = this.config.redirectURL
311
-
312
- const res = await this.graphqlQuery({
313
- query: `
314
- mutation magicLinkLogin($data: MagicLinkLoginInput!) { magic_link_login(params: $data) { message }}
315
- `,
316
- variables: { data },
317
- })
318
-
319
- return res.magic_link_login
320
- }
321
- catch (err) {
322
- throw new Error(err)
323
- }
324
- }
325
-
326
- oauthLogin = async (
327
- oauthProvider: string,
328
- roles?: string[],
329
- redirect_uri?: string,
330
- state?: string,
331
- ): Promise<void> => {
332
- let urlState = state
333
- if (!urlState)
334
- urlState = encode(createRandomString())
335
-
336
- // @ts-expect-error
337
- if (!Object.values(Types.OAuthProviders).includes(oauthProvider)) {
338
- throw new Error(
339
- `only following oauth providers are supported: ${Object.values(
340
- oauthProvider,
341
- ).toString()}`,
342
- )
343
- }
344
- if (!hasWindow())
345
- throw new Error('oauthLogin is only supported for browsers')
346
-
347
- window.location.replace(
348
- `${this.config.authorizerURL}/oauth_login/${oauthProvider}?redirect_uri=${
349
- redirect_uri || this.config.redirectURL
350
- }&state=${urlState}${
351
- (roles && roles.length) ? `&roles=${roles.join(',')}` : ''
352
- }`,
353
- )
354
- }
355
-
356
- resendOtp = async (
357
- data: Types.ResendOtpInput,
358
- ): Promise<Types.Response | void> => {
359
- try {
360
- const res = await this.graphqlQuery({
361
- query: `
362
- mutation resendOtp($data: ResendOTPRequest!) { resend_otp(params: $data) { message }}
363
- `,
364
- variables: { data },
365
- })
366
-
367
- return res.resend_otp
368
- }
369
- catch (err) {
370
- throw new Error(err)
371
- }
372
- }
373
-
374
- resetPassword = async (
375
- data: Types.ResetPasswordInput,
376
- ): Promise<Types.Response | void> => {
377
- try {
378
- const resetPasswordRes = await this.graphqlQuery({
379
- query: 'mutation resetPassword($data: ResetPasswordInput!) { reset_password(params: $data) { message } }',
380
- variables: {
381
- data,
382
- },
383
- })
384
- return resetPasswordRes.reset_password
385
- }
386
- catch (error) {
387
- throw new Error(error)
388
- }
389
- }
390
-
391
- revokeToken = async (data: { refresh_token: string }) => {
392
- if (!data.refresh_token && !data.refresh_token.trim())
393
- throw new Error('Invalid refresh_token')
394
-
395
- const fetcher = getFetcher()
396
- const res = await fetcher(`${this.config.authorizerURL}/oauth/revoke`, {
397
- method: 'POST',
398
- headers: {
399
- ...this.config.extraHeaders,
400
- },
401
- body: JSON.stringify({
402
- refresh_token: data.refresh_token,
403
- client_id: this.config.clientID,
404
- }),
405
- })
406
-
407
- return await res.json()
408
- }
409
-
410
- signup = async (data: Types.SignupInput): Promise<Types.AuthToken | void> => {
411
- try {
412
- const res = await this.graphqlQuery({
413
- query: `
414
- mutation signup($data: SignUpInput!) { signup(params: $data) { ${authTokenFragment}}}
415
- `,
416
- variables: { data },
417
- })
418
-
419
- return res.signup
420
- }
421
- catch (err) {
422
- throw new Error(err)
423
- }
424
- }
425
-
426
- updateProfile = async (
427
- data: Types.UpdateProfileInput,
428
- headers?: Types.Headers,
429
- ): Promise<Types.Response | void> => {
430
- try {
431
- const updateProfileRes = await this.graphqlQuery({
432
- query: 'mutation updateProfile($data: UpdateProfileInput!) { update_profile(params: $data) { message } }',
433
- headers,
434
- variables: {
435
- data,
436
- },
437
- })
438
-
439
- return updateProfileRes.update_profile
440
- }
441
- catch (error) {
442
- throw new Error(error)
443
- }
444
- }
445
-
446
- validateJWTToken = async (
447
- params?: Types.ValidateJWTTokenInput,
448
- ): Promise<Types.ValidateJWTTokenResponse> => {
449
- try {
450
- const res = await this.graphqlQuery({
451
- query: 'query validateJWTToken($params: ValidateJWTTokenInput!){validate_jwt_token(params: $params) { is_valid claims } }',
452
- variables: {
453
- params,
454
- },
455
- })
456
-
457
- return res.validate_jwt_token
458
- }
459
- catch (error) {
460
- throw new Error(error)
461
- }
462
- }
463
-
464
- verifyEmail = async (
465
- data: Types.VerifyEmailInput,
466
- ): Promise<Types.AuthToken | void> => {
467
- try {
468
- const res = await this.graphqlQuery({
469
- query: `
470
- mutation verifyEmail($data: VerifyEmailInput!) { verify_email(params: $data) { ${authTokenFragment}}}
471
- `,
472
- variables: { data },
473
- })
474
-
475
- return res.verify_email
476
- }
477
- catch (err) {
478
- throw new Error(err)
479
- }
480
- }
481
-
482
- verifyOtp = async (
483
- data: Types.VerifyOtpInput,
484
- ): Promise<Types.AuthToken | void> => {
485
- try {
486
- const res = await this.graphqlQuery({
487
- query: `
488
- mutation verifyOtp($data: VerifyOTPRequest!) { verify_otp(params: $data) { ${authTokenFragment}}}
489
- `,
490
- variables: { data },
491
- })
492
-
493
- return res.verify_otp
494
- }
495
- catch (err) {
496
- throw new Error(err)
497
- }
498
- }
499
- }
package/src/types.ts DELETED
@@ -1,203 +0,0 @@
1
- export interface ConfigType {
2
- authorizerURL: string
3
- redirectURL: string
4
- clientID: string
5
- extraHeaders?: Record<string, string>
6
- }
7
-
8
- export interface User {
9
- id: string
10
- email: string
11
- preferred_username: string
12
- email_verified: boolean
13
- signup_methods: string
14
- given_name?: string | null
15
- family_name?: string | null
16
- middle_name?: string | null
17
- nickname?: string | null
18
- picture?: string | null
19
- gender?: string | null
20
- birthdate?: string | null
21
- phone_number?: string | null
22
- phone_number_verified?: boolean | null
23
- roles?: string[]
24
- created_at: number
25
- updated_at: number
26
- is_multi_factor_auth_enabled?: boolean
27
- }
28
-
29
- export interface AuthToken {
30
- message?: string
31
- access_token: string
32
- expires_in: number
33
- id_token: string
34
- refresh_token?: string
35
- user?: User
36
- should_show_otp_screen?: boolean
37
- }
38
-
39
- export interface Response {
40
- message: string
41
- }
42
-
43
- export type Headers = Record<string, string>
44
-
45
- export interface LoginInput {
46
- email: string
47
- password: string
48
- roles?: string[]
49
- scope?: string[]
50
- state?: string
51
- }
52
-
53
- export interface SignupInput {
54
- email: string
55
- password: string
56
- confirm_password: string
57
- given_name?: string
58
- family_name?: string
59
- middle_name?: string
60
- nickname?: string
61
- picture?: string
62
- gender?: string
63
- birthdate?: string
64
- phone_number?: string
65
- roles?: string[]
66
- scope?: string[]
67
- redirect_uri?: string
68
- is_multi_factor_auth_enabled?: boolean
69
- state?: string
70
- }
71
-
72
- export interface MagicLinkLoginInput {
73
- email: string
74
- roles?: string[]
75
- scopes?: string[]
76
- state?: string
77
- redirect_uri?: string
78
- }
79
-
80
- export interface VerifyEmailInput { token: string; state?: string }
81
-
82
- export interface VerifyOtpInput { email: string; otp: string; state?: string }
83
-
84
- export interface ResendOtpInput { email: string }
85
-
86
- export interface GraphqlQueryInput {
87
- query: string
88
- variables?: Record<string, any>
89
- headers?: Headers
90
- }
91
-
92
- export interface MetaData {
93
- version: string
94
- client_id: string
95
- is_google_login_enabled: boolean
96
- is_facebook_login_enabled: boolean
97
- is_github_login_enabled: boolean
98
- is_linkedin_login_enabled: boolean
99
- is_apple_login_enabled: boolean
100
- is_twitter_login_enabled: boolean
101
- is_microsoft_login_enabled: boolean
102
- is_email_verification_enabled: boolean
103
- is_basic_authentication_enabled: boolean
104
- is_magic_link_login_enabled: boolean
105
- is_sign_up_enabled: boolean
106
- is_strong_password_enabled: boolean
107
- }
108
-
109
- export interface UpdateProfileInput {
110
- old_password?: string
111
- new_password?: string
112
- confirm_new_password?: string
113
- email?: string
114
- given_name?: string
115
- family_name?: string
116
- middle_name?: string
117
- nickname?: string
118
- gender?: string
119
- birthdate?: string
120
- phone_number?: string
121
- picture?: string
122
- is_multi_factor_auth_enabled?: boolean
123
- }
124
-
125
- export interface ForgotPasswordInput {
126
- email: string
127
- state?: string
128
- redirect_uri?: string
129
- }
130
-
131
- export interface ResetPasswordInput {
132
- token: string
133
- password: string
134
- confirm_password: string
135
- }
136
-
137
- export interface SessionQueryInput {
138
- roles?: string[]
139
- }
140
-
141
- export interface IsValidJWTQueryInput {
142
- jwt: string
143
- roles?: string[]
144
- }
145
-
146
- export interface ValidJWTResponse {
147
- valid: string
148
- message: string
149
- }
150
-
151
- export enum OAuthProviders {
152
- Apple = 'apple',
153
- Github = 'github',
154
- Google = 'google',
155
- Facebook = 'facebook',
156
- LinkedIn = 'linkedin',
157
- }
158
-
159
- export enum ResponseTypes {
160
- Code = 'code',
161
- Token = 'token',
162
- }
163
-
164
- export interface AuthorizeInput {
165
- response_type: ResponseTypes
166
- use_refresh_token?: boolean
167
- response_mode?: string
168
- }
169
-
170
- export interface AuthorizeResponse {
171
- state: string
172
- code?: string
173
- error?: string
174
- error_description?: string
175
- }
176
-
177
- export interface RevokeTokenInput {
178
- refresh_token: string
179
- }
180
-
181
- export interface GetTokenInput {
182
- code?: string
183
- grant_type?: string
184
- refresh_token?: string
185
- }
186
-
187
- export interface GetTokenResponse {
188
- access_token: string
189
- expires_in: number
190
- id_token: string
191
- refresh_token?: string
192
- }
193
-
194
- export interface ValidateJWTTokenInput {
195
- token_type: 'access_token' | 'id_token' | 'refresh_token'
196
- token: string
197
- roles?: string[]
198
- }
199
-
200
- export interface ValidateJWTTokenResponse {
201
- is_valid: boolean
202
- claims: Record<string, any>
203
- }