@shware/security 7.1.1 → 8.0.1

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.
Files changed (132) hide show
  1. package/README.md +113 -32
  2. package/dist/auth/attributes.cjs +4 -3
  3. package/dist/auth/attributes.cjs.map +1 -1
  4. package/dist/auth/attributes.d.cts +3 -3
  5. package/dist/auth/attributes.d.cts.map +1 -1
  6. package/dist/auth/attributes.d.mts +3 -3
  7. package/dist/auth/attributes.d.mts.map +1 -1
  8. package/dist/auth/attributes.mjs +4 -3
  9. package/dist/auth/attributes.mjs.map +1 -1
  10. package/dist/auth/desktop-codes.cjs +57 -0
  11. package/dist/auth/desktop-codes.cjs.map +1 -0
  12. package/dist/auth/desktop-codes.d.cts +24 -0
  13. package/dist/auth/desktop-codes.d.cts.map +1 -0
  14. package/dist/auth/desktop-codes.d.mts +24 -0
  15. package/dist/auth/desktop-codes.d.mts.map +1 -0
  16. package/dist/auth/desktop-codes.mjs +55 -0
  17. package/dist/auth/desktop-codes.mjs.map +1 -0
  18. package/dist/auth/email-codes.cjs +77 -0
  19. package/dist/auth/email-codes.cjs.map +1 -0
  20. package/dist/auth/email-codes.d.cts +39 -0
  21. package/dist/auth/email-codes.d.cts.map +1 -0
  22. package/dist/auth/email-codes.d.mts +39 -0
  23. package/dist/auth/email-codes.d.mts.map +1 -0
  24. package/dist/auth/email-codes.mjs +75 -0
  25. package/dist/auth/email-codes.mjs.map +1 -0
  26. package/dist/auth/error.cjs +47 -0
  27. package/dist/auth/error.cjs.map +1 -0
  28. package/dist/auth/error.d.cts +88 -0
  29. package/dist/auth/error.d.cts.map +1 -0
  30. package/dist/auth/error.d.mts +88 -0
  31. package/dist/auth/error.d.mts.map +1 -0
  32. package/dist/auth/error.mjs +45 -0
  33. package/dist/auth/error.mjs.map +1 -0
  34. package/dist/auth/index.cjs +249 -384
  35. package/dist/auth/index.cjs.map +1 -1
  36. package/dist/auth/index.d.cts +66 -55
  37. package/dist/auth/index.d.cts.map +1 -1
  38. package/dist/auth/index.d.mts +66 -55
  39. package/dist/auth/index.d.mts.map +1 -1
  40. package/dist/auth/index.mjs +252 -387
  41. package/dist/auth/index.mjs.map +1 -1
  42. package/dist/auth/respond.cjs +99 -0
  43. package/dist/auth/respond.cjs.map +1 -0
  44. package/dist/auth/respond.d.cts +39 -0
  45. package/dist/auth/respond.d.cts.map +1 -0
  46. package/dist/auth/respond.d.mts +39 -0
  47. package/dist/auth/respond.d.mts.map +1 -0
  48. package/dist/auth/respond.mjs +92 -0
  49. package/dist/auth/respond.mjs.map +1 -0
  50. package/dist/auth/types.d.cts +27 -11
  51. package/dist/auth/types.d.cts.map +1 -1
  52. package/dist/auth/types.d.mts +27 -11
  53. package/dist/auth/types.d.mts.map +1 -1
  54. package/dist/index.cjs +5 -0
  55. package/dist/index.d.cts +4 -1
  56. package/dist/index.d.mts +4 -1
  57. package/dist/index.mjs +3 -1
  58. package/dist/oauth2/error.cjs +0 -7
  59. package/dist/oauth2/error.cjs.map +1 -1
  60. package/dist/oauth2/error.d.cts +0 -3
  61. package/dist/oauth2/error.d.cts.map +1 -1
  62. package/dist/oauth2/error.d.mts +0 -3
  63. package/dist/oauth2/error.d.mts.map +1 -1
  64. package/dist/oauth2/error.mjs +1 -7
  65. package/dist/oauth2/error.mjs.map +1 -1
  66. package/dist/oauth2/provider/common.cjs +17 -3
  67. package/dist/oauth2/provider/common.cjs.map +1 -1
  68. package/dist/oauth2/provider/common.d.cts.map +1 -1
  69. package/dist/oauth2/provider/common.d.mts.map +1 -1
  70. package/dist/oauth2/provider/common.mjs +17 -3
  71. package/dist/oauth2/provider/common.mjs.map +1 -1
  72. package/dist/oauth2/provider/facebook.cjs +2 -4
  73. package/dist/oauth2/provider/facebook.cjs.map +1 -1
  74. package/dist/oauth2/provider/facebook.d.cts +0 -1
  75. package/dist/oauth2/provider/facebook.d.cts.map +1 -1
  76. package/dist/oauth2/provider/facebook.d.mts +0 -1
  77. package/dist/oauth2/provider/facebook.d.mts.map +1 -1
  78. package/dist/oauth2/provider/facebook.mjs +2 -4
  79. package/dist/oauth2/provider/facebook.mjs.map +1 -1
  80. package/dist/oauth2/provider/github.cjs +1 -1
  81. package/dist/oauth2/provider/github.cjs.map +1 -1
  82. package/dist/oauth2/provider/github.d.cts +1 -1
  83. package/dist/oauth2/provider/github.d.cts.map +1 -1
  84. package/dist/oauth2/provider/github.d.mts +1 -1
  85. package/dist/oauth2/provider/github.d.mts.map +1 -1
  86. package/dist/oauth2/provider/github.mjs +1 -1
  87. package/dist/oauth2/provider/github.mjs.map +1 -1
  88. package/dist/oauth2/provider/x.cjs +6 -4
  89. package/dist/oauth2/provider/x.cjs.map +1 -1
  90. package/dist/oauth2/provider/x.d.cts +3 -2
  91. package/dist/oauth2/provider/x.d.cts.map +1 -1
  92. package/dist/oauth2/provider/x.d.mts +3 -2
  93. package/dist/oauth2/provider/x.d.mts.map +1 -1
  94. package/dist/oauth2/provider/x.mjs +6 -4
  95. package/dist/oauth2/provider/x.mjs.map +1 -1
  96. package/dist/oauth2/types.cjs.map +1 -1
  97. package/dist/oauth2/types.d.cts +5 -0
  98. package/dist/oauth2/types.d.cts.map +1 -1
  99. package/dist/oauth2/types.d.mts +5 -0
  100. package/dist/oauth2/types.d.mts.map +1 -1
  101. package/dist/oauth2/types.mjs.map +1 -1
  102. package/dist/session/common.cjs +10 -13
  103. package/dist/session/common.cjs.map +1 -1
  104. package/dist/session/common.d.cts +7 -3
  105. package/dist/session/common.d.cts.map +1 -1
  106. package/dist/session/common.d.mts +7 -3
  107. package/dist/session/common.d.mts.map +1 -1
  108. package/dist/session/common.mjs +10 -12
  109. package/dist/session/common.mjs.map +1 -1
  110. package/dist/session/db.cjs +2 -2
  111. package/dist/session/db.cjs.map +1 -1
  112. package/dist/session/db.mjs +3 -3
  113. package/dist/session/db.mjs.map +1 -1
  114. package/dist/session/redis.cjs +6 -8
  115. package/dist/session/redis.cjs.map +1 -1
  116. package/dist/session/redis.d.cts.map +1 -1
  117. package/dist/session/redis.d.mts.map +1 -1
  118. package/dist/session/redis.mjs +7 -9
  119. package/dist/session/redis.mjs.map +1 -1
  120. package/dist/session/types.d.cts +0 -12
  121. package/dist/session/types.d.cts.map +1 -1
  122. package/dist/session/types.d.mts +0 -12
  123. package/dist/session/types.d.mts.map +1 -1
  124. package/dist/utils/valid.cjs +34 -52
  125. package/dist/utils/valid.cjs.map +1 -1
  126. package/dist/utils/valid.d.cts +8 -23
  127. package/dist/utils/valid.d.cts.map +1 -1
  128. package/dist/utils/valid.d.mts +8 -23
  129. package/dist/utils/valid.d.mts.map +1 -1
  130. package/dist/utils/valid.mjs +32 -50
  131. package/dist/utils/valid.mjs.map +1 -1
  132. package/package.json +3 -3
@@ -1,5 +1,6 @@
1
1
  import { Principal } from "../core/index.cjs";
2
2
  import { KVRepository, Session, SessionRepository } from "../session/types.cjs";
3
+ import { EmailSender } from "./email-codes.cjs";
3
4
  import { OAuth2ClientConfig, OAuth2Token, UserInfo } from "../oauth2/types.cjs";
4
5
  import { CookieOptions } from "../utils/http.cjs";
5
6
  export type LoggedHandler = (principal: Principal) => Promise<void>;
@@ -24,7 +25,11 @@ export interface Authorization {
24
25
  token?: OAuth2Token;
25
26
  attributes: Record<string, string>;
26
27
  }
27
- /** Creates or updates the user and returns the principal whose `name` the session stores. */
28
+ /**
29
+ * Creates or updates the user and returns the principal whose `name` the session stores. Throw an
30
+ * `AuthenticationError` to refuse the sign-in with a reason the client can act on; any other error
31
+ * is treated as a server fault.
32
+ */
28
33
  export type AuthorizedHandler = (request: Request, authorization: Authorization) => Promise<Principal>;
29
34
  export interface OAuth2AuthorizationOptions {
30
35
  /**
@@ -56,13 +61,24 @@ export interface AuthConfig {
56
61
  * 3600 (an hour); `0` writes on every authenticated request.
57
62
  */
58
63
  touchInterval?: number;
64
+ /**
65
+ * Also carry the session id in the `X-Auth-Token` header, for clients without a cookie jar
66
+ * (a CLI, a desktop shell), as Spring Session's `HeaderHttpSessionIdResolver` does: every
67
+ * response that sets the session cookie (a login, `logged`) also answers `X-Auth-Token: <id>`,
68
+ * and a request without the cookie is read from the same header. Default `false`. Turning it
69
+ * on exposes the id to same-origin scripts, which the cookie's `HttpOnly` kept it from, and a
70
+ * cross-origin client needs the header in `Access-Control-Expose-Headers`. The header is for
71
+ * the session id only: an API token for programmatic access is a different credential and
72
+ * is not read here.
73
+ */
74
+ header?: boolean;
59
75
  };
60
76
  turnstileSecretKey?: string;
61
77
  /** Limits of email verification codes (a code itself is valid for 10 minutes). */
62
78
  verificationCode?: {
63
79
  /**
64
80
  * Wrong guesses a code survives: once a login exceeds this many attempts the code is discarded
65
- * and `loginEmail` answers `VERIFICATION_CODE_ATTEMPTS_EXCEEDED`. Default 5.
81
+ * and `loginEmail` answers `403 VERIFICATION_CODE_ATTEMPTS_EXCEEDED`. Default 5.
66
82
  */
67
83
  maxAttempts?: number;
68
84
  /**
@@ -96,16 +112,16 @@ export interface AuthService {
96
112
  loginOAuth2Code: (request: Request, onAuthorized: AuthorizedHandler) => Promise<Response>;
97
113
  loginOAuth2Native: (request: Request, onAuthorized: AuthorizedHandler) => Promise<Response>;
98
114
  loginOAuth2Onetap: (request: Request, onAuthorized: AuthorizedHandler, provider?: string) => Promise<Response>;
99
- sendEmailVerificationCode: (request: Request, sender: (data: {
100
- email: string;
101
- verificationCode: string;
102
- }) => Promise<void>) => Promise<Response>;
103
- sendPhoneVerificationCode: (request: Request, sender: (data: {
104
- phone: string;
105
- verificationCode: string;
106
- }) => Promise<void>) => Promise<Response>;
115
+ sendEmailVerificationCode: (request: Request, sender: EmailSender) => Promise<Response>;
107
116
  loginEmail: (request: Request, onAuthorized: AuthorizedHandler) => Promise<Response>;
108
- loginPhone: (request: Request, onAuthorized: AuthorizedHandler) => Promise<Response>;
117
+ /**
118
+ * Spends a mailed code without signing in, for a host flow that only needs proof of the address
119
+ * (verifying or changing a signed-in user's email). Throws `AuthenticationError`
120
+ * (`INVALID_VERIFICATION_CODE`, `VERIFICATION_CODE_ATTEMPTS_EXCEEDED`) as `loginEmail` answers.
121
+ */
122
+ verifyEmailCode: (email: string, verificationCode: string) => Promise<void>;
123
+ desktopAuthorize: (request: Request) => Promise<Response>;
124
+ desktopExchange: (request: Request) => Promise<Response>;
109
125
  kick: (principal: Principal) => Promise<void>;
110
126
  isAuthenticated: (request: Request) => Promise<boolean>;
111
127
  getSession: <T extends boolean>(request: Request, create: T) => Promise<T extends true ? Session : Session | null>;
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.cts","names":[],"sources":["../../src/auth/types.ts"],"mappings":";;;;YAKY,iBAAiB,WAAW,cAAc;;;;;;;;;;;;;;;iBAerC;EACf;EACA;EACA,UAAU;EACV,QAAQ;EACR,YAAY;;;YAIF,qBACV,SAAS,SACT,eAAe,kBACZ,QAAQ;iBAEI;;;;;;;;;;;EAWf,aAAa;;iBAGE;EACf;EACA,cAAc;EACd,mBAAmB;EACnB,SAAS;IAAkB;;EAC3B;;;;;;;;;IASE;;EAEF;;EAEA;;;;;IAKE;;;;;IAKA;;EAEF;IACE,SAAS;;IAET;;;;;;;;MAQE;;;;iBAKW;EAEf,OAAO,SAAS,YAAY,QAAQ;EACpC,SAAS,SAAS,YAAY,QAAQ;EACtC,SAAS,SAAS,SAAS,WAAW,kBAAkB,QAAQ;EAGhE,cAAc,SAAS,YAAY,QAAQ;EAC3C,cAAc,SAAS,YAAY,QAAQ;EAC3C,sBACE,SAAS,SACT,UAAU,+BACP,QAAQ;EACb,kBAAkB,SAAS,SAAS,cAAc,sBAAsB,QAAQ;EAChF,oBAAoB,SAAS,SAAS,cAAc,sBAAsB,QAAQ;EAClF,oBACE,SAAS,SACT,cAAc,mBACd,sBACG,QAAQ;EAGb,4BACE,SAAS,SACT,SAAS;IAAQ;IAAe;QAA+B,kBAC5D,QAAQ;EACb,4BACE,SAAS,SACT,SAAS;IAAQ;IAAe;QAA+B,kBAC5D,QAAQ;EAEb,aAAa,SAAS,SAAS,cAAc,sBAAsB,QAAQ;EAC3E,aAAa,SAAS,SAAS,cAAc,sBAAsB,QAAQ;EAG3E,OAAO,WAAW,cAAc;EAChC,kBAAkB,SAAS,YAAY;EACvC,aAAa,mBACX,SAAS,SACT,QAAQ,MACL,QAAQ,iBAAiB,UAAU;EACxC,gBAAgB,sBAAsB;EACtC,eAAe,SAAS,YAAY,QAAQ;EAC5C,eAAe,WAAW,cAAc,QAAQ;EAChD,yBAAyB,0BAA0B,QAAQ"}
1
+ {"version":3,"file":"types.d.cts","names":[],"sources":["../../src/auth/types.ts"],"mappings":";;;;;YAMY,iBAAiB,WAAW,cAAc;;;;;;;;;;;;;;;iBAerC;EACf;EACA;EACA,UAAU;EACV,QAAQ;EACR,YAAY;;;;;;;YAQF,qBACV,SAAS,SACT,eAAe,kBACZ,QAAQ;iBAEI;;;;;;;;;;;EAWf,aAAa;;iBAGE;EACf;EACA,cAAc;EACd,mBAAmB;EACnB,SAAS;IAAkB;;EAC3B;;;;;;;;;IASE;;;;;;;;;;;IAWA;;EAEF;;EAEA;;;;;IAKE;;;;;IAKA;;EAEF;IACE,SAAS;;IAET;;;;;;;;MAQE;;;;iBAKW;EAEf,OAAO,SAAS,YAAY,QAAQ;EACpC,SAAS,SAAS,YAAY,QAAQ;EACtC,SAAS,SAAS,SAAS,WAAW,kBAAkB,QAAQ;EAGhE,cAAc,SAAS,YAAY,QAAQ;EAC3C,cAAc,SAAS,YAAY,QAAQ;EAC3C,sBACE,SAAS,SACT,UAAU,+BACP,QAAQ;EACb,kBAAkB,SAAS,SAAS,cAAc,sBAAsB,QAAQ;EAChF,oBAAoB,SAAS,SAAS,cAAc,sBAAsB,QAAQ;EAClF,oBACE,SAAS,SACT,cAAc,mBACd,sBACG,QAAQ;EAGb,4BAA4B,SAAS,SAAS,QAAQ,gBAAgB,QAAQ;EAC9E,aAAa,SAAS,SAAS,cAAc,sBAAsB,QAAQ;;;;;;EAM3E,kBAAkB,eAAe,6BAA6B;EAG9D,mBAAmB,SAAS,YAAY,QAAQ;EAChD,kBAAkB,SAAS,YAAY,QAAQ;EAG/C,OAAO,WAAW,cAAc;EAChC,kBAAkB,SAAS,YAAY;EACvC,aAAa,mBACX,SAAS,SACT,QAAQ,MACL,QAAQ,iBAAiB,UAAU;EACxC,gBAAgB,sBAAsB;EACtC,eAAe,SAAS,YAAY,QAAQ;EAC5C,eAAe,WAAW,cAAc,QAAQ;EAChD,yBAAyB,0BAA0B,QAAQ"}
@@ -1,5 +1,6 @@
1
1
  import { Principal } from "../core/index.mjs";
2
2
  import { KVRepository, Session, SessionRepository } from "../session/types.mjs";
3
+ import { EmailSender } from "./email-codes.mjs";
3
4
  import { OAuth2ClientConfig, OAuth2Token, UserInfo } from "../oauth2/types.mjs";
4
5
  import { CookieOptions } from "../utils/http.mjs";
5
6
  export type LoggedHandler = (principal: Principal) => Promise<void>;
@@ -24,7 +25,11 @@ export interface Authorization {
24
25
  token?: OAuth2Token;
25
26
  attributes: Record<string, string>;
26
27
  }
27
- /** Creates or updates the user and returns the principal whose `name` the session stores. */
28
+ /**
29
+ * Creates or updates the user and returns the principal whose `name` the session stores. Throw an
30
+ * `AuthenticationError` to refuse the sign-in with a reason the client can act on; any other error
31
+ * is treated as a server fault.
32
+ */
28
33
  export type AuthorizedHandler = (request: Request, authorization: Authorization) => Promise<Principal>;
29
34
  export interface OAuth2AuthorizationOptions {
30
35
  /**
@@ -56,13 +61,24 @@ export interface AuthConfig {
56
61
  * 3600 (an hour); `0` writes on every authenticated request.
57
62
  */
58
63
  touchInterval?: number;
64
+ /**
65
+ * Also carry the session id in the `X-Auth-Token` header, for clients without a cookie jar
66
+ * (a CLI, a desktop shell), as Spring Session's `HeaderHttpSessionIdResolver` does: every
67
+ * response that sets the session cookie (a login, `logged`) also answers `X-Auth-Token: <id>`,
68
+ * and a request without the cookie is read from the same header. Default `false`. Turning it
69
+ * on exposes the id to same-origin scripts, which the cookie's `HttpOnly` kept it from, and a
70
+ * cross-origin client needs the header in `Access-Control-Expose-Headers`. The header is for
71
+ * the session id only: an API token for programmatic access is a different credential and
72
+ * is not read here.
73
+ */
74
+ header?: boolean;
59
75
  };
60
76
  turnstileSecretKey?: string;
61
77
  /** Limits of email verification codes (a code itself is valid for 10 minutes). */
62
78
  verificationCode?: {
63
79
  /**
64
80
  * Wrong guesses a code survives: once a login exceeds this many attempts the code is discarded
65
- * and `loginEmail` answers `VERIFICATION_CODE_ATTEMPTS_EXCEEDED`. Default 5.
81
+ * and `loginEmail` answers `403 VERIFICATION_CODE_ATTEMPTS_EXCEEDED`. Default 5.
66
82
  */
67
83
  maxAttempts?: number;
68
84
  /**
@@ -96,16 +112,16 @@ export interface AuthService {
96
112
  loginOAuth2Code: (request: Request, onAuthorized: AuthorizedHandler) => Promise<Response>;
97
113
  loginOAuth2Native: (request: Request, onAuthorized: AuthorizedHandler) => Promise<Response>;
98
114
  loginOAuth2Onetap: (request: Request, onAuthorized: AuthorizedHandler, provider?: string) => Promise<Response>;
99
- sendEmailVerificationCode: (request: Request, sender: (data: {
100
- email: string;
101
- verificationCode: string;
102
- }) => Promise<void>) => Promise<Response>;
103
- sendPhoneVerificationCode: (request: Request, sender: (data: {
104
- phone: string;
105
- verificationCode: string;
106
- }) => Promise<void>) => Promise<Response>;
115
+ sendEmailVerificationCode: (request: Request, sender: EmailSender) => Promise<Response>;
107
116
  loginEmail: (request: Request, onAuthorized: AuthorizedHandler) => Promise<Response>;
108
- loginPhone: (request: Request, onAuthorized: AuthorizedHandler) => Promise<Response>;
117
+ /**
118
+ * Spends a mailed code without signing in, for a host flow that only needs proof of the address
119
+ * (verifying or changing a signed-in user's email). Throws `AuthenticationError`
120
+ * (`INVALID_VERIFICATION_CODE`, `VERIFICATION_CODE_ATTEMPTS_EXCEEDED`) as `loginEmail` answers.
121
+ */
122
+ verifyEmailCode: (email: string, verificationCode: string) => Promise<void>;
123
+ desktopAuthorize: (request: Request) => Promise<Response>;
124
+ desktopExchange: (request: Request) => Promise<Response>;
109
125
  kick: (principal: Principal) => Promise<void>;
110
126
  isAuthenticated: (request: Request) => Promise<boolean>;
111
127
  getSession: <T extends boolean>(request: Request, create: T) => Promise<T extends true ? Session : Session | null>;
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.mts","names":[],"sources":["../../src/auth/types.ts"],"mappings":";;;;YAKY,iBAAiB,WAAW,cAAc;;;;;;;;;;;;;;;iBAerC;EACf;EACA;EACA,UAAU;EACV,QAAQ;EACR,YAAY;;;YAIF,qBACV,SAAS,SACT,eAAe,kBACZ,QAAQ;iBAEI;;;;;;;;;;;EAWf,aAAa;;iBAGE;EACf;EACA,cAAc;EACd,mBAAmB;EACnB,SAAS;IAAkB;;EAC3B;;;;;;;;;IASE;;EAEF;;EAEA;;;;;IAKE;;;;;IAKA;;EAEF;IACE,SAAS;;IAET;;;;;;;;MAQE;;;;iBAKW;EAEf,OAAO,SAAS,YAAY,QAAQ;EACpC,SAAS,SAAS,YAAY,QAAQ;EACtC,SAAS,SAAS,SAAS,WAAW,kBAAkB,QAAQ;EAGhE,cAAc,SAAS,YAAY,QAAQ;EAC3C,cAAc,SAAS,YAAY,QAAQ;EAC3C,sBACE,SAAS,SACT,UAAU,+BACP,QAAQ;EACb,kBAAkB,SAAS,SAAS,cAAc,sBAAsB,QAAQ;EAChF,oBAAoB,SAAS,SAAS,cAAc,sBAAsB,QAAQ;EAClF,oBACE,SAAS,SACT,cAAc,mBACd,sBACG,QAAQ;EAGb,4BACE,SAAS,SACT,SAAS;IAAQ;IAAe;QAA+B,kBAC5D,QAAQ;EACb,4BACE,SAAS,SACT,SAAS;IAAQ;IAAe;QAA+B,kBAC5D,QAAQ;EAEb,aAAa,SAAS,SAAS,cAAc,sBAAsB,QAAQ;EAC3E,aAAa,SAAS,SAAS,cAAc,sBAAsB,QAAQ;EAG3E,OAAO,WAAW,cAAc;EAChC,kBAAkB,SAAS,YAAY;EACvC,aAAa,mBACX,SAAS,SACT,QAAQ,MACL,QAAQ,iBAAiB,UAAU;EACxC,gBAAgB,sBAAsB;EACtC,eAAe,SAAS,YAAY,QAAQ;EAC5C,eAAe,WAAW,cAAc,QAAQ;EAChD,yBAAyB,0BAA0B,QAAQ"}
1
+ {"version":3,"file":"types.d.mts","names":[],"sources":["../../src/auth/types.ts"],"mappings":";;;;;YAMY,iBAAiB,WAAW,cAAc;;;;;;;;;;;;;;;iBAerC;EACf;EACA;EACA,UAAU;EACV,QAAQ;EACR,YAAY;;;;;;;YAQF,qBACV,SAAS,SACT,eAAe,kBACZ,QAAQ;iBAEI;;;;;;;;;;;EAWf,aAAa;;iBAGE;EACf;EACA,cAAc;EACd,mBAAmB;EACnB,SAAS;IAAkB;;EAC3B;;;;;;;;;IASE;;;;;;;;;;;IAWA;;EAEF;;EAEA;;;;;IAKE;;;;;IAKA;;EAEF;IACE,SAAS;;IAET;;;;;;;;MAQE;;;;iBAKW;EAEf,OAAO,SAAS,YAAY,QAAQ;EACpC,SAAS,SAAS,YAAY,QAAQ;EACtC,SAAS,SAAS,SAAS,WAAW,kBAAkB,QAAQ;EAGhE,cAAc,SAAS,YAAY,QAAQ;EAC3C,cAAc,SAAS,YAAY,QAAQ;EAC3C,sBACE,SAAS,SACT,UAAU,+BACP,QAAQ;EACb,kBAAkB,SAAS,SAAS,cAAc,sBAAsB,QAAQ;EAChF,oBAAoB,SAAS,SAAS,cAAc,sBAAsB,QAAQ;EAClF,oBACE,SAAS,SACT,cAAc,mBACd,sBACG,QAAQ;EAGb,4BAA4B,SAAS,SAAS,QAAQ,gBAAgB,QAAQ;EAC9E,aAAa,SAAS,SAAS,cAAc,sBAAsB,QAAQ;;;;;;EAM3E,kBAAkB,eAAe,6BAA6B;EAG9D,mBAAmB,SAAS,YAAY,QAAQ;EAChD,kBAAkB,SAAS,YAAY,QAAQ;EAG/C,OAAO,WAAW,cAAc;EAChC,kBAAkB,SAAS,YAAY;EACvC,aAAa,mBACX,SAAS,SACT,QAAQ,MACL,QAAQ,iBAAiB,UAAU;EACxC,gBAAgB,sBAAsB;EACtC,eAAe,SAAS,YAAY,QAAQ;EAC5C,eAAe,WAAW,cAAc,QAAQ;EAChD,yBAAyB,0BAA0B,QAAQ"}
package/dist/index.cjs CHANGED
@@ -1,5 +1,7 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ const require_auth_error = require("./auth/error.cjs");
2
3
  const require_oauth2_error = require("./oauth2/error.cjs");
4
+ const require_auth_respond = require("./auth/respond.cjs");
3
5
  const require_oauth2_client = require("./oauth2/client.cjs");
4
6
  const require_session_common = require("./session/common.cjs");
5
7
  const require_auth_index = require("./auth/index.cjs");
@@ -8,7 +10,9 @@ const require_session_db = require("./session/db.cjs");
8
10
  const require_core_index = require("./core/index.cjs");
9
11
  const require_oauth2_types = require("./oauth2/types.cjs");
10
12
  const require_oauth2_name = require("./oauth2/name.cjs");
13
+ exports.AUTHENTICATION_REASONS = require_auth_error.AUTHENTICATION_REASONS;
11
14
  exports.Auth = require_auth_index.Auth;
15
+ exports.AuthenticationError = require_auth_error.AuthenticationError;
12
16
  exports.DBIndexedSessionRepository = require_session_db.DBIndexedSessionRepository;
13
17
  exports.MAX_NAME_PART_LENGTH = require_oauth2_name.MAX_NAME_PART_LENGTH;
14
18
  exports.OAuth2Client = require_oauth2_client.OAuth2Client;
@@ -20,4 +24,5 @@ exports.PROVIDERS = require_core_index.PROVIDERS;
20
24
  exports.RedisIndexedSessionRepository = require_session_redis.RedisIndexedSessionRepository;
21
25
  exports.RedisKVRepository = require_session_redis.RedisKVRepository;
22
26
  exports.composeName = require_oauth2_name.composeName;
27
+ exports.errorResponse = require_auth_respond.errorResponse;
23
28
  exports.oauth2RedirectQuerySchema = require_oauth2_client.oauth2RedirectQuerySchema;
package/dist/index.d.cts CHANGED
@@ -1,12 +1,15 @@
1
1
  import { CsrfToken, PROVIDERS, Principal, Provider } from "./core/index.cjs";
2
2
  import { KVRepository, Namespace, Session, SessionRepository } from "./session/types.cjs";
3
+ import { EmailSender } from "./auth/email-codes.cjs";
4
+ import { AUTHENTICATION_REASONS, AuthenticationError, AuthenticationReason, AuthenticationReasons } from "./auth/error.cjs";
3
5
  import { AuthorizationResponse, ClientSecret, NativeClient, NativeCredential, OAuth2ClientConfig, OAuth2Token, OIDC_SCOPES, OidcScope, OidcToken, PersonNameComponents, ProviderConfig, StandardClaims, UserInfo, WebClient } from "./oauth2/types.cjs";
4
6
  import { AuthConfig, AuthService, Authorization, AuthorizedHandler, OAuth2AuthorizationOptions } from "./auth/types.cjs";
5
7
  import { Auth, PATH } from "./auth/index.cjs";
8
+ import { ErrorBody, errorResponse } from "./auth/respond.cjs";
6
9
  import { OAuth2Client, oauth2RedirectQuerySchema } from "./oauth2/client.cjs";
7
10
  import { OAuth2Error, OAuth2ErrorType } from "./oauth2/error.cjs";
8
11
  import { RedisIndexedSessionRepository, RedisKVRepository } from "./session/redis.cjs";
9
12
  import { DBAdapter, DBIndexedSessionRepository } from "./session/db.cjs";
10
13
  import { PRINCIPAL_NAME_INDEX_NAME } from "./session/common.cjs";
11
14
  import { MAX_NAME_PART_LENGTH, composeName } from "./oauth2/name.cjs";
12
- export { Auth, type AuthConfig, type AuthService, type Authorization, type AuthorizationResponse, type AuthorizedHandler, type ClientSecret, type CsrfToken, type DBAdapter, DBIndexedSessionRepository, type KVRepository, MAX_NAME_PART_LENGTH, type Namespace, type NativeClient, type NativeCredential, type OAuth2AuthorizationOptions, OAuth2Client, type OAuth2ClientConfig, OAuth2Error, type OAuth2ErrorType, type OAuth2Token, OIDC_SCOPES, type OidcScope, type OidcToken, PATH, PRINCIPAL_NAME_INDEX_NAME, PROVIDERS, type PersonNameComponents, type Principal, type Provider, type ProviderConfig, RedisIndexedSessionRepository, RedisKVRepository, type Session, type SessionRepository, type StandardClaims, type UserInfo, type WebClient, composeName, oauth2RedirectQuerySchema };
15
+ export { AUTHENTICATION_REASONS, Auth, type AuthConfig, type AuthService, AuthenticationError, type AuthenticationReason, type AuthenticationReasons, type Authorization, type AuthorizationResponse, type AuthorizedHandler, type ClientSecret, type CsrfToken, type DBAdapter, DBIndexedSessionRepository, type EmailSender, type ErrorBody, type KVRepository, MAX_NAME_PART_LENGTH, type Namespace, type NativeClient, type NativeCredential, type OAuth2AuthorizationOptions, OAuth2Client, type OAuth2ClientConfig, OAuth2Error, type OAuth2ErrorType, type OAuth2Token, OIDC_SCOPES, type OidcScope, type OidcToken, PATH, PRINCIPAL_NAME_INDEX_NAME, PROVIDERS, type PersonNameComponents, type Principal, type Provider, type ProviderConfig, RedisIndexedSessionRepository, RedisKVRepository, type Session, type SessionRepository, type StandardClaims, type UserInfo, type WebClient, composeName, errorResponse, oauth2RedirectQuerySchema };
package/dist/index.d.mts CHANGED
@@ -1,12 +1,15 @@
1
1
  import { CsrfToken, PROVIDERS, Principal, Provider } from "./core/index.mjs";
2
2
  import { KVRepository, Namespace, Session, SessionRepository } from "./session/types.mjs";
3
+ import { EmailSender } from "./auth/email-codes.mjs";
4
+ import { AUTHENTICATION_REASONS, AuthenticationError, AuthenticationReason, AuthenticationReasons } from "./auth/error.mjs";
3
5
  import { AuthorizationResponse, ClientSecret, NativeClient, NativeCredential, OAuth2ClientConfig, OAuth2Token, OIDC_SCOPES, OidcScope, OidcToken, PersonNameComponents, ProviderConfig, StandardClaims, UserInfo, WebClient } from "./oauth2/types.mjs";
4
6
  import { AuthConfig, AuthService, Authorization, AuthorizedHandler, OAuth2AuthorizationOptions } from "./auth/types.mjs";
5
7
  import { Auth, PATH } from "./auth/index.mjs";
8
+ import { ErrorBody, errorResponse } from "./auth/respond.mjs";
6
9
  import { OAuth2Client, oauth2RedirectQuerySchema } from "./oauth2/client.mjs";
7
10
  import { OAuth2Error, OAuth2ErrorType } from "./oauth2/error.mjs";
8
11
  import { RedisIndexedSessionRepository, RedisKVRepository } from "./session/redis.mjs";
9
12
  import { DBAdapter, DBIndexedSessionRepository } from "./session/db.mjs";
10
13
  import { PRINCIPAL_NAME_INDEX_NAME } from "./session/common.mjs";
11
14
  import { MAX_NAME_PART_LENGTH, composeName } from "./oauth2/name.mjs";
12
- export { Auth, type AuthConfig, type AuthService, type Authorization, type AuthorizationResponse, type AuthorizedHandler, type ClientSecret, type CsrfToken, type DBAdapter, DBIndexedSessionRepository, type KVRepository, MAX_NAME_PART_LENGTH, type Namespace, type NativeClient, type NativeCredential, type OAuth2AuthorizationOptions, OAuth2Client, type OAuth2ClientConfig, OAuth2Error, type OAuth2ErrorType, type OAuth2Token, OIDC_SCOPES, type OidcScope, type OidcToken, PATH, PRINCIPAL_NAME_INDEX_NAME, PROVIDERS, type PersonNameComponents, type Principal, type Provider, type ProviderConfig, RedisIndexedSessionRepository, RedisKVRepository, type Session, type SessionRepository, type StandardClaims, type UserInfo, type WebClient, composeName, oauth2RedirectQuerySchema };
15
+ export { AUTHENTICATION_REASONS, Auth, type AuthConfig, type AuthService, AuthenticationError, type AuthenticationReason, type AuthenticationReasons, type Authorization, type AuthorizationResponse, type AuthorizedHandler, type ClientSecret, type CsrfToken, type DBAdapter, DBIndexedSessionRepository, type EmailSender, type ErrorBody, type KVRepository, MAX_NAME_PART_LENGTH, type Namespace, type NativeClient, type NativeCredential, type OAuth2AuthorizationOptions, OAuth2Client, type OAuth2ClientConfig, OAuth2Error, type OAuth2ErrorType, type OAuth2Token, OIDC_SCOPES, type OidcScope, type OidcToken, PATH, PRINCIPAL_NAME_INDEX_NAME, PROVIDERS, type PersonNameComponents, type Principal, type Provider, type ProviderConfig, RedisIndexedSessionRepository, RedisKVRepository, type Session, type SessionRepository, type StandardClaims, type UserInfo, type WebClient, composeName, errorResponse, oauth2RedirectQuerySchema };
package/dist/index.mjs CHANGED
@@ -1,4 +1,6 @@
1
+ import { AUTHENTICATION_REASONS, AuthenticationError } from "./auth/error.mjs";
1
2
  import { OAuth2Error } from "./oauth2/error.mjs";
3
+ import { errorResponse } from "./auth/respond.mjs";
2
4
  import { OAuth2Client, oauth2RedirectQuerySchema } from "./oauth2/client.mjs";
3
5
  import { PRINCIPAL_NAME_INDEX_NAME } from "./session/common.mjs";
4
6
  import { Auth, PATH } from "./auth/index.mjs";
@@ -7,4 +9,4 @@ import { DBIndexedSessionRepository } from "./session/db.mjs";
7
9
  import { PROVIDERS } from "./core/index.mjs";
8
10
  import { OIDC_SCOPES } from "./oauth2/types.mjs";
9
11
  import { MAX_NAME_PART_LENGTH, composeName } from "./oauth2/name.mjs";
10
- export { Auth, DBIndexedSessionRepository, MAX_NAME_PART_LENGTH, OAuth2Client, OAuth2Error, OIDC_SCOPES, PATH, PRINCIPAL_NAME_INDEX_NAME, PROVIDERS, RedisIndexedSessionRepository, RedisKVRepository, composeName, oauth2RedirectQuerySchema };
12
+ export { AUTHENTICATION_REASONS, Auth, AuthenticationError, DBIndexedSessionRepository, MAX_NAME_PART_LENGTH, OAuth2Client, OAuth2Error, OIDC_SCOPES, PATH, PRINCIPAL_NAME_INDEX_NAME, PROVIDERS, RedisIndexedSessionRepository, RedisKVRepository, composeName, errorResponse, oauth2RedirectQuerySchema };
@@ -29,13 +29,6 @@ var OAuth2Error = class OAuth2Error extends Error {
29
29
  Object.setPrototypeOf(this, OAuth2Error.prototype);
30
30
  }
31
31
  };
32
- var AuthenticationError = class AuthenticationError extends Error {
33
- constructor(message) {
34
- super(message);
35
- Object.setPrototypeOf(this, AuthenticationError.prototype);
36
- }
37
- };
38
- exports.AuthenticationError = AuthenticationError;
39
32
  exports.OAuth2Error = OAuth2Error;
40
33
  exports.isKnownOAuth2ErrorType = isKnownOAuth2ErrorType;
41
34
 
@@ -1 +1 @@
1
- {"version":3,"file":"error.cjs","names":[],"sources":["../../src/oauth2/error.ts"],"sourcesContent":["// reference: https://datatracker.ietf.org/doc/html/rfc6749#section-4.2.2.1\nexport type OAuth2ErrorType =\n | 'invalid_request' // 400\n | 'invalid_client' // 401\n | 'invalid_grant' // 400\n | 'invalid_token' // 401\n | 'invalid_scope' // 400\n | 'unauthorized_client' // 401\n | 'unsupported_grant_type' // 400\n | 'unsupported_response_type' // 400\n | 'insufficient_scope' // 403\n | 'redirect_uri_mismatch' // 400\n | 'access_denied' // 400\n | 'server_error' // 500\n | 'temporarily_unavailable' // 503\n | (string & {});\n\n/** The registered error codes of `OAuth2ErrorType`, for checking untrusted input at runtime. */\nconst OAUTH2_ERROR_TYPES: ReadonlySet<string> = new Set([\n 'invalid_request',\n 'invalid_client',\n 'invalid_grant',\n 'invalid_token',\n 'invalid_scope',\n 'unauthorized_client',\n 'unsupported_grant_type',\n 'unsupported_response_type',\n 'insufficient_scope',\n 'redirect_uri_mismatch',\n 'access_denied',\n 'server_error',\n 'temporarily_unavailable',\n]);\n\nexport function isKnownOAuth2ErrorType(value: string): boolean {\n return OAUTH2_ERROR_TYPES.has(value);\n}\n\nexport class OAuth2Error extends Error {\n readonly status: number;\n readonly error: OAuth2ErrorType;\n\n constructor(status: number, error: OAuth2ErrorType, message?: string) {\n super(message ?? `OAuth2 error: ${error}`);\n this.status = status;\n this.error = error;\n Object.setPrototypeOf(this, OAuth2Error.prototype);\n }\n}\n\nexport class AuthenticationError extends Error {\n constructor(message: string) {\n super(message);\n Object.setPrototypeOf(this, AuthenticationError.prototype);\n }\n}\n"],"mappings":";;;AAkBA,MAAM,qCAA0C,IAAI,IAAI;CACtD;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF,CAAC;AAED,SAAgB,uBAAuB,OAAwB;CAC7D,OAAO,mBAAmB,IAAI,KAAK;AACrC;AAEA,IAAa,cAAb,MAAa,oBAAoB,MAAM;CACrC;CACA;CAEA,YAAY,QAAgB,OAAwB,SAAkB;EACpE,MAAM,WAAW,iBAAiB,OAAO;EACzC,KAAK,SAAS;EACd,KAAK,QAAQ;EACb,OAAO,eAAe,MAAM,YAAY,SAAS;CACnD;AACF;AAEA,IAAa,sBAAb,MAAa,4BAA4B,MAAM;CAC7C,YAAY,SAAiB;EAC3B,MAAM,OAAO;EACb,OAAO,eAAe,MAAM,oBAAoB,SAAS;CAC3D;AACF"}
1
+ {"version":3,"file":"error.cjs","names":[],"sources":["../../src/oauth2/error.ts"],"sourcesContent":["// reference: https://datatracker.ietf.org/doc/html/rfc6749#section-4.2.2.1\nexport type OAuth2ErrorType =\n | 'invalid_request' // 400\n | 'invalid_client' // 401\n | 'invalid_grant' // 400\n | 'invalid_token' // 401\n | 'invalid_scope' // 400\n | 'unauthorized_client' // 401\n | 'unsupported_grant_type' // 400\n | 'unsupported_response_type' // 400\n | 'insufficient_scope' // 403\n | 'redirect_uri_mismatch' // 400\n | 'access_denied' // 400\n | 'server_error' // 500\n | 'temporarily_unavailable' // 503\n | (string & {});\n\n/** The registered error codes of `OAuth2ErrorType`, for checking untrusted input at runtime. */\nconst OAUTH2_ERROR_TYPES: ReadonlySet<string> = new Set([\n 'invalid_request',\n 'invalid_client',\n 'invalid_grant',\n 'invalid_token',\n 'invalid_scope',\n 'unauthorized_client',\n 'unsupported_grant_type',\n 'unsupported_response_type',\n 'insufficient_scope',\n 'redirect_uri_mismatch',\n 'access_denied',\n 'server_error',\n 'temporarily_unavailable',\n]);\n\nexport function isKnownOAuth2ErrorType(value: string): boolean {\n return OAUTH2_ERROR_TYPES.has(value);\n}\n\nexport class OAuth2Error extends Error {\n readonly status: number;\n readonly error: OAuth2ErrorType;\n\n constructor(status: number, error: OAuth2ErrorType, message?: string) {\n super(message ?? `OAuth2 error: ${error}`);\n this.status = status;\n this.error = error;\n Object.setPrototypeOf(this, OAuth2Error.prototype);\n }\n}\n"],"mappings":";;;AAkBA,MAAM,qCAA0C,IAAI,IAAI;CACtD;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF,CAAC;AAED,SAAgB,uBAAuB,OAAwB;CAC7D,OAAO,mBAAmB,IAAI,KAAK;AACrC;AAEA,IAAa,cAAb,MAAa,oBAAoB,MAAM;CACrC;CACA;CAEA,YAAY,QAAgB,OAAwB,SAAkB;EACpE,MAAM,WAAW,iBAAiB,OAAO;EACzC,KAAK,SAAS;EACd,KAAK,QAAQ;EACb,OAAO,eAAe,MAAM,YAAY,SAAS;CACnD;AACF"}
@@ -5,7 +5,4 @@ export declare class OAuth2Error extends Error {
5
5
  readonly error: OAuth2ErrorType;
6
6
  constructor(status: number, error: OAuth2ErrorType, message?: string);
7
7
  }
8
- export declare class AuthenticationError extends Error {
9
- constructor(message: string);
10
- }
11
8
  //# sourceMappingURL=error.d.cts.map
@@ -1 +1 @@
1
- {"version":3,"file":"error.d.cts","names":[],"sources":["../../src/oauth2/error.ts"],"mappings":"A,YACY;wBAiCI,uBAAuB;qBAI1B,oBAAoB;WACtB;WACA,OAAO;EAEhB,YAAY,gBAAgB,OAAO,iBAAiB;;qBAQzC,4BAA4B;EACvC,YAAY"}
1
+ {"version":3,"file":"error.d.cts","names":[],"sources":["../../src/oauth2/error.ts"],"mappings":"A,YACY;wBAiCI,uBAAuB;qBAI1B,oBAAoB;WACtB;WACA,OAAO;EAEhB,YAAY,gBAAgB,OAAO,iBAAiB"}
@@ -5,7 +5,4 @@ export declare class OAuth2Error extends Error {
5
5
  readonly error: OAuth2ErrorType;
6
6
  constructor(status: number, error: OAuth2ErrorType, message?: string);
7
7
  }
8
- export declare class AuthenticationError extends Error {
9
- constructor(message: string);
10
- }
11
8
  //# sourceMappingURL=error.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"error.d.mts","names":[],"sources":["../../src/oauth2/error.ts"],"mappings":"A,YACY;wBAiCI,uBAAuB;qBAI1B,oBAAoB;WACtB;WACA,OAAO;EAEhB,YAAY,gBAAgB,OAAO,iBAAiB;;qBAQzC,4BAA4B;EACvC,YAAY"}
1
+ {"version":3,"file":"error.d.mts","names":[],"sources":["../../src/oauth2/error.ts"],"mappings":"A,YACY;wBAiCI,uBAAuB;qBAI1B,oBAAoB;WACtB;WACA,OAAO;EAEhB,YAAY,gBAAgB,OAAO,iBAAiB"}
@@ -28,12 +28,6 @@ var OAuth2Error = class OAuth2Error extends Error {
28
28
  Object.setPrototypeOf(this, OAuth2Error.prototype);
29
29
  }
30
30
  };
31
- var AuthenticationError = class AuthenticationError extends Error {
32
- constructor(message) {
33
- super(message);
34
- Object.setPrototypeOf(this, AuthenticationError.prototype);
35
- }
36
- };
37
- export { AuthenticationError, OAuth2Error, isKnownOAuth2ErrorType };
31
+ export { OAuth2Error, isKnownOAuth2ErrorType };
38
32
 
39
33
  //# sourceMappingURL=error.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"error.mjs","names":[],"sources":["../../src/oauth2/error.ts"],"sourcesContent":["// reference: https://datatracker.ietf.org/doc/html/rfc6749#section-4.2.2.1\nexport type OAuth2ErrorType =\n | 'invalid_request' // 400\n | 'invalid_client' // 401\n | 'invalid_grant' // 400\n | 'invalid_token' // 401\n | 'invalid_scope' // 400\n | 'unauthorized_client' // 401\n | 'unsupported_grant_type' // 400\n | 'unsupported_response_type' // 400\n | 'insufficient_scope' // 403\n | 'redirect_uri_mismatch' // 400\n | 'access_denied' // 400\n | 'server_error' // 500\n | 'temporarily_unavailable' // 503\n | (string & {});\n\n/** The registered error codes of `OAuth2ErrorType`, for checking untrusted input at runtime. */\nconst OAUTH2_ERROR_TYPES: ReadonlySet<string> = new Set([\n 'invalid_request',\n 'invalid_client',\n 'invalid_grant',\n 'invalid_token',\n 'invalid_scope',\n 'unauthorized_client',\n 'unsupported_grant_type',\n 'unsupported_response_type',\n 'insufficient_scope',\n 'redirect_uri_mismatch',\n 'access_denied',\n 'server_error',\n 'temporarily_unavailable',\n]);\n\nexport function isKnownOAuth2ErrorType(value: string): boolean {\n return OAUTH2_ERROR_TYPES.has(value);\n}\n\nexport class OAuth2Error extends Error {\n readonly status: number;\n readonly error: OAuth2ErrorType;\n\n constructor(status: number, error: OAuth2ErrorType, message?: string) {\n super(message ?? `OAuth2 error: ${error}`);\n this.status = status;\n this.error = error;\n Object.setPrototypeOf(this, OAuth2Error.prototype);\n }\n}\n\nexport class AuthenticationError extends Error {\n constructor(message: string) {\n super(message);\n Object.setPrototypeOf(this, AuthenticationError.prototype);\n }\n}\n"],"mappings":";;AAkBA,MAAM,qCAA0C,IAAI,IAAI;CACtD;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF,CAAC;AAED,SAAgB,uBAAuB,OAAwB;CAC7D,OAAO,mBAAmB,IAAI,KAAK;AACrC;AAEA,IAAa,cAAb,MAAa,oBAAoB,MAAM;CACrC;CACA;CAEA,YAAY,QAAgB,OAAwB,SAAkB;EACpE,MAAM,WAAW,iBAAiB,OAAO;EACzC,KAAK,SAAS;EACd,KAAK,QAAQ;EACb,OAAO,eAAe,MAAM,YAAY,SAAS;CACnD;AACF;AAEA,IAAa,sBAAb,MAAa,4BAA4B,MAAM;CAC7C,YAAY,SAAiB;EAC3B,MAAM,OAAO;EACb,OAAO,eAAe,MAAM,oBAAoB,SAAS;CAC3D;AACF"}
1
+ {"version":3,"file":"error.mjs","names":[],"sources":["../../src/oauth2/error.ts"],"sourcesContent":["// reference: https://datatracker.ietf.org/doc/html/rfc6749#section-4.2.2.1\nexport type OAuth2ErrorType =\n | 'invalid_request' // 400\n | 'invalid_client' // 401\n | 'invalid_grant' // 400\n | 'invalid_token' // 401\n | 'invalid_scope' // 400\n | 'unauthorized_client' // 401\n | 'unsupported_grant_type' // 400\n | 'unsupported_response_type' // 400\n | 'insufficient_scope' // 403\n | 'redirect_uri_mismatch' // 400\n | 'access_denied' // 400\n | 'server_error' // 500\n | 'temporarily_unavailable' // 503\n | (string & {});\n\n/** The registered error codes of `OAuth2ErrorType`, for checking untrusted input at runtime. */\nconst OAUTH2_ERROR_TYPES: ReadonlySet<string> = new Set([\n 'invalid_request',\n 'invalid_client',\n 'invalid_grant',\n 'invalid_token',\n 'invalid_scope',\n 'unauthorized_client',\n 'unsupported_grant_type',\n 'unsupported_response_type',\n 'insufficient_scope',\n 'redirect_uri_mismatch',\n 'access_denied',\n 'server_error',\n 'temporarily_unavailable',\n]);\n\nexport function isKnownOAuth2ErrorType(value: string): boolean {\n return OAUTH2_ERROR_TYPES.has(value);\n}\n\nexport class OAuth2Error extends Error {\n readonly status: number;\n readonly error: OAuth2ErrorType;\n\n constructor(status: number, error: OAuth2ErrorType, message?: string) {\n super(message ?? `OAuth2 error: ${error}`);\n this.status = status;\n this.error = error;\n Object.setPrototypeOf(this, OAuth2Error.prototype);\n }\n}\n"],"mappings":";;AAkBA,MAAM,qCAA0C,IAAI,IAAI;CACtD;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF,CAAC;AAED,SAAgB,uBAAuB,OAAwB;CAC7D,OAAO,mBAAmB,IAAI,KAAK;AACrC;AAEA,IAAa,cAAb,MAAa,oBAAoB,MAAM;CACrC;CACA;CAEA,YAAY,QAAgB,OAAwB,SAAkB;EACpE,MAAM,WAAW,iBAAiB,OAAO;EACzC,KAAK,SAAS;EACd,KAAK,QAAQ;EACb,OAAO,eAAe,MAAM,YAAY,SAAS;CACnD;AACF"}
@@ -75,14 +75,28 @@ async function revokeToken(params) {
75
75
  });
76
76
  if (!response.ok) {
77
77
  const error = await response.json();
78
- console.error("Refresh token error:", error);
78
+ console.error("Revoke token error:", error);
79
79
  throw new require_oauth2_error.OAuth2Error(response.status, "invalid_request", "Failed to revoke token");
80
80
  }
81
81
  }
82
+ /**
83
+ * One key set per JWKS endpoint for the life of the process: jose caches the fetched keys,
84
+ * refetches on an unknown `kid` (with a cooldown) and when they go stale, so a set created per
85
+ * call would refetch the keys for every id token.
86
+ */
87
+ const jwkSets = /* @__PURE__ */ new Map();
88
+ function remoteJWKSet(jwkSetUri) {
89
+ let jwks = jwkSets.get(jwkSetUri);
90
+ if (!jwks) {
91
+ jwks = (0, jose.createRemoteJWKSet)(new URL(jwkSetUri));
92
+ jwkSets.set(jwkSetUri, jwks);
93
+ }
94
+ return jwks;
95
+ }
82
96
  async function verifyIdToken(idToken, options) {
83
97
  const { jwkSetUri, issuer, audience } = options;
84
98
  try {
85
- const jwks = (0, jose.createRemoteJWKSet)(new URL(jwkSetUri));
99
+ const jwks = remoteJWKSet(jwkSetUri);
86
100
  const { payload } = await (0, jose.jwtVerify)(idToken, jwks, {
87
101
  issuer,
88
102
  audience
@@ -90,7 +104,7 @@ async function verifyIdToken(idToken, options) {
90
104
  return payload;
91
105
  } catch (error) {
92
106
  console.error("Failed to verify id_token", error);
93
- throw new require_oauth2_error.OAuth2Error(400, "invalid_request", "Failed to verify id_token");
107
+ throw new require_oauth2_error.OAuth2Error(400, "invalid_grant", "Failed to verify id_token");
94
108
  }
95
109
  }
96
110
  exports.createAuthorizationUri = createAuthorizationUri;
@@ -1 +1 @@
1
- {"version":3,"file":"common.cjs","names":["OAuth2Error","createRemoteJWKSet","jwtVerify"],"sources":["../../../src/oauth2/provider/common.ts"],"sourcesContent":["import { createRemoteJWKSet, jwtVerify } from 'jose';\nimport { OAuth2Error } from '../error';\nimport type { ExchangeCodeParams, PkceParameters, RefreshTokenParams } from '../types';\n\nexport function createAuthorizationUri(options: {\n state: string;\n scope: string[];\n clientId: string;\n redirectUri: string;\n authorizationUri: string;\n pkce?: Omit<PkceParameters, 'code_verifier'>;\n}) {\n const url = new URL(options.authorizationUri);\n url.searchParams.append('response_type', 'code');\n url.searchParams.append('client_id', options.clientId);\n url.searchParams.append('state', options.state);\n url.searchParams.append('scope', options.scope.join(' '));\n url.searchParams.append('redirect_uri', options.redirectUri);\n if (options.pkce) {\n url.searchParams.append('code_challenge_method', options.pkce.code_challenge_method);\n url.searchParams.append('code_challenge', options.pkce.code_challenge);\n }\n return url;\n}\n\nexport async function exchangeAuthorizationCode(\n params: ExchangeCodeParams & {\n tokenUri: string;\n authentication?: 'basic' | 'post';\n /** Extra request headers some providers require, e.g. GitHub's `User-Agent`. */\n headers?: Record<string, string>;\n }\n) {\n const body = new URLSearchParams();\n body.append('code', params.code);\n body.append('redirect_uri', params.redirectUri);\n body.append('grant_type', 'authorization_code');\n if (params.pkce) body.append('code_verifier', params.pkce.code_verifier);\n\n const headers: Record<string, string> = {\n ...params.headers,\n Accept: 'application/json',\n 'Content-Type': 'application/x-www-form-urlencoded',\n };\n if (params.authentication === 'basic') {\n const token = Buffer.from(`${params.clientId}:${params.clientSecret ?? ''}`).toString('base64');\n headers.Authorization = `Basic ${token}`;\n } else {\n body.append('client_id', params.clientId);\n // Public clients (Google's installed-app clients, PKCE-only clients) have no secret.\n if (params.clientSecret) body.append('client_secret', params.clientSecret);\n }\n\n return fetch(params.tokenUri, { method: 'POST', headers, body });\n}\n\nexport async function refreshAccessToken(\n params: RefreshTokenParams & {\n tokenUri: string;\n authentication?: 'basic' | 'post';\n }\n) {\n const body = new URLSearchParams();\n body.append('grant_type', 'refresh_token');\n body.append('refresh_token', params.refreshToken);\n\n const headers: Record<string, string> = {\n Accept: 'application/json',\n 'Content-Type': 'application/x-www-form-urlencoded',\n };\n\n if (params.authentication === 'basic') {\n const token = Buffer.from(`${params.clientId}:${params.clientSecret ?? ''}`).toString('base64');\n headers.Authorization = `Basic ${token}`;\n } else {\n body.append('client_id', params.clientId);\n if (params.clientSecret) body.append('client_secret', params.clientSecret);\n }\n\n return fetch(params.tokenUri, { method: 'POST', headers, body });\n}\n\ninterface RevokeTokenParams {\n token: string;\n clientId: string;\n clientSecret?: string;\n tokenRevokeUri: string;\n authentication?: 'basic' | 'post';\n}\n\nexport async function revokeToken(params: RevokeTokenParams) {\n const body = new URLSearchParams();\n body.append('token', params.token);\n const headers: Record<string, string> = {\n Accept: 'application/json',\n 'Content-Type': 'application/x-www-form-urlencoded',\n };\n\n if (params.authentication === 'basic') {\n const token = Buffer.from(`${params.clientId}:${params.clientSecret ?? ''}`).toString('base64');\n headers.Authorization = `Basic ${token}`;\n } else {\n body.append('client_id', params.clientId);\n if (params.clientSecret) body.append('client_secret', params.clientSecret);\n }\n\n const response = await fetch(params.tokenRevokeUri, { method: 'POST', headers, body });\n if (!response.ok) {\n const error = await response.json();\n console.error('Refresh token error:', error);\n throw new OAuth2Error(response.status, 'invalid_request', 'Failed to revoke token');\n }\n}\n\nexport interface VerifyIdTokenOptions {\n jwkSetUri: string;\n /** The `iss` values the provider signs with; anything else is refused. */\n issuer: string | string[];\n /**\n * The client the token must be issued to. An id token proves who the user is only to the client\n * it names in `aud`: any other app on the same identity provider can obtain a validly signed one\n * for the same user, so a token for a foreign client must never sign anyone in here.\n */\n audience: string;\n}\n\nexport async function verifyIdToken<T>(idToken: string, options: VerifyIdTokenOptions) {\n const { jwkSetUri, issuer, audience } = options;\n try {\n const jwks = createRemoteJWKSet(new URL(jwkSetUri));\n const { payload } = await jwtVerify(idToken, jwks, { issuer, audience });\n return payload as T;\n } catch (error) {\n console.error('Failed to verify id_token', error);\n throw new OAuth2Error(400, 'invalid_request', 'Failed to verify id_token');\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"common.cjs","names":["OAuth2Error","createRemoteJWKSet","jwtVerify"],"sources":["../../../src/oauth2/provider/common.ts"],"sourcesContent":["import { createRemoteJWKSet, jwtVerify } from 'jose';\nimport { OAuth2Error } from '../error';\nimport type { ExchangeCodeParams, PkceParameters, RefreshTokenParams } from '../types';\n\nexport function createAuthorizationUri(options: {\n state: string;\n scope: string[];\n clientId: string;\n redirectUri: string;\n authorizationUri: string;\n pkce?: Omit<PkceParameters, 'code_verifier'>;\n}) {\n const url = new URL(options.authorizationUri);\n url.searchParams.append('response_type', 'code');\n url.searchParams.append('client_id', options.clientId);\n url.searchParams.append('state', options.state);\n url.searchParams.append('scope', options.scope.join(' '));\n url.searchParams.append('redirect_uri', options.redirectUri);\n if (options.pkce) {\n url.searchParams.append('code_challenge_method', options.pkce.code_challenge_method);\n url.searchParams.append('code_challenge', options.pkce.code_challenge);\n }\n return url;\n}\n\nexport async function exchangeAuthorizationCode(\n params: ExchangeCodeParams & {\n tokenUri: string;\n authentication?: 'basic' | 'post';\n /** Extra request headers some providers require, e.g. GitHub's `User-Agent`. */\n headers?: Record<string, string>;\n }\n) {\n const body = new URLSearchParams();\n body.append('code', params.code);\n body.append('redirect_uri', params.redirectUri);\n body.append('grant_type', 'authorization_code');\n if (params.pkce) body.append('code_verifier', params.pkce.code_verifier);\n\n const headers: Record<string, string> = {\n ...params.headers,\n Accept: 'application/json',\n 'Content-Type': 'application/x-www-form-urlencoded',\n };\n if (params.authentication === 'basic') {\n const token = Buffer.from(`${params.clientId}:${params.clientSecret ?? ''}`).toString('base64');\n headers.Authorization = `Basic ${token}`;\n } else {\n body.append('client_id', params.clientId);\n // Public clients (Google's installed-app clients, PKCE-only clients) have no secret.\n if (params.clientSecret) body.append('client_secret', params.clientSecret);\n }\n\n return fetch(params.tokenUri, { method: 'POST', headers, body });\n}\n\nexport async function refreshAccessToken(\n params: RefreshTokenParams & {\n tokenUri: string;\n authentication?: 'basic' | 'post';\n }\n) {\n const body = new URLSearchParams();\n body.append('grant_type', 'refresh_token');\n body.append('refresh_token', params.refreshToken);\n\n const headers: Record<string, string> = {\n Accept: 'application/json',\n 'Content-Type': 'application/x-www-form-urlencoded',\n };\n\n if (params.authentication === 'basic') {\n const token = Buffer.from(`${params.clientId}:${params.clientSecret ?? ''}`).toString('base64');\n headers.Authorization = `Basic ${token}`;\n } else {\n body.append('client_id', params.clientId);\n if (params.clientSecret) body.append('client_secret', params.clientSecret);\n }\n\n return fetch(params.tokenUri, { method: 'POST', headers, body });\n}\n\ninterface RevokeTokenParams {\n token: string;\n clientId: string;\n clientSecret?: string;\n tokenRevokeUri: string;\n authentication?: 'basic' | 'post';\n}\n\nexport async function revokeToken(params: RevokeTokenParams) {\n const body = new URLSearchParams();\n body.append('token', params.token);\n const headers: Record<string, string> = {\n Accept: 'application/json',\n 'Content-Type': 'application/x-www-form-urlencoded',\n };\n\n if (params.authentication === 'basic') {\n const token = Buffer.from(`${params.clientId}:${params.clientSecret ?? ''}`).toString('base64');\n headers.Authorization = `Basic ${token}`;\n } else {\n body.append('client_id', params.clientId);\n if (params.clientSecret) body.append('client_secret', params.clientSecret);\n }\n\n const response = await fetch(params.tokenRevokeUri, { method: 'POST', headers, body });\n if (!response.ok) {\n const error = await response.json();\n console.error('Revoke token error:', error);\n throw new OAuth2Error(response.status, 'invalid_request', 'Failed to revoke token');\n }\n}\n\nexport interface VerifyIdTokenOptions {\n jwkSetUri: string;\n /** The `iss` values the provider signs with; anything else is refused. */\n issuer: string | string[];\n /**\n * The client the token must be issued to. An id token proves who the user is only to the client\n * it names in `aud`: any other app on the same identity provider can obtain a validly signed one\n * for the same user, so a token for a foreign client must never sign anyone in here.\n */\n audience: string;\n}\n\n/**\n * One key set per JWKS endpoint for the life of the process: jose caches the fetched keys,\n * refetches on an unknown `kid` (with a cooldown) and when they go stale, so a set created per\n * call would refetch the keys for every id token.\n */\nconst jwkSets = new Map<string, ReturnType<typeof createRemoteJWKSet>>();\n\nfunction remoteJWKSet(jwkSetUri: string) {\n let jwks = jwkSets.get(jwkSetUri);\n if (!jwks) {\n jwks = createRemoteJWKSet(new URL(jwkSetUri));\n jwkSets.set(jwkSetUri, jwks);\n }\n return jwks;\n}\n\nexport async function verifyIdToken<T>(idToken: string, options: VerifyIdTokenOptions) {\n const { jwkSetUri, issuer, audience } = options;\n try {\n const jwks = remoteJWKSet(jwkSetUri);\n const { payload } = await jwtVerify(idToken, jwks, { issuer, audience });\n return payload as T;\n } catch (error) {\n console.error('Failed to verify id_token', error);\n // The token is the grant here: one for another audience or issuer is an invalid grant, not a\n // malformed request.\n throw new OAuth2Error(400, 'invalid_grant', 'Failed to verify id_token');\n }\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"common.d.cts","names":[],"sources":["../../../src/oauth2/provider/common.ts"],"mappings":";wBAIgB,uBAAuB;EACrC;EACA;EACA;EACA;EACA;EACA,OAAO,KAAK;IACb;wBAcqB,0BACpB,QAAQ;EACN;EACA;;EAEA,UAAU;IACX,QAAA;wBAyBmB,mBACpB,QAAQ;EACN;EACA;IACD,QAAA;UAsBO;EACR;EACA;EACA;EACA;EACA;;wBAGoB,YAAY,QAAQ,oBAAiB;iBAwB1C;EACf;;EAEA;;;;;;EAMA;;wBAGoB,cAAc,GAAG,iBAAiB,SAAS,uBAAoB,QAAA"}
1
+ {"version":3,"file":"common.d.cts","names":[],"sources":["../../../src/oauth2/provider/common.ts"],"mappings":";wBAIgB,uBAAuB;EACrC;EACA;EACA;EACA;EACA;EACA,OAAO,KAAK;IACb;wBAcqB,0BACpB,QAAQ;EACN;EACA;;EAEA,UAAU;IACX,QAAA;wBAyBmB,mBACpB,QAAQ;EACN;EACA;IACD,QAAA;UAsBO;EACR;EACA;EACA;EACA;EACA;;wBAGoB,YAAY,QAAQ,oBAAiB;iBAwB1C;EACf;;EAEA;;;;;;EAMA;;wBAmBoB,cAAc,GAAG,iBAAiB,SAAS,uBAAoB,QAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"common.d.mts","names":[],"sources":["../../../src/oauth2/provider/common.ts"],"mappings":";wBAIgB,uBAAuB;EACrC;EACA;EACA;EACA;EACA;EACA,OAAO,KAAK;IACb;wBAcqB,0BACpB,QAAQ;EACN;EACA;;EAEA,UAAU;IACX,QAAA;wBAyBmB,mBACpB,QAAQ;EACN;EACA;IACD,QAAA;UAsBO;EACR;EACA;EACA;EACA;EACA;;wBAGoB,YAAY,QAAQ,oBAAiB;iBAwB1C;EACf;;EAEA;;;;;;EAMA;;wBAGoB,cAAc,GAAG,iBAAiB,SAAS,uBAAoB,QAAA"}
1
+ {"version":3,"file":"common.d.mts","names":[],"sources":["../../../src/oauth2/provider/common.ts"],"mappings":";wBAIgB,uBAAuB;EACrC;EACA;EACA;EACA;EACA;EACA,OAAO,KAAK;IACb;wBAcqB,0BACpB,QAAQ;EACN;EACA;;EAEA,UAAU;IACX,QAAA;wBAyBmB,mBACpB,QAAQ;EACN;EACA;IACD,QAAA;UAsBO;EACR;EACA;EACA;EACA;EACA;;wBAGoB,YAAY,QAAQ,oBAAiB;iBAwB1C;EACf;;EAEA;;;;;;EAMA;;wBAmBoB,cAAc,GAAG,iBAAiB,SAAS,uBAAoB,QAAA"}
@@ -74,14 +74,28 @@ async function revokeToken(params) {
74
74
  });
75
75
  if (!response.ok) {
76
76
  const error = await response.json();
77
- console.error("Refresh token error:", error);
77
+ console.error("Revoke token error:", error);
78
78
  throw new OAuth2Error(response.status, "invalid_request", "Failed to revoke token");
79
79
  }
80
80
  }
81
+ /**
82
+ * One key set per JWKS endpoint for the life of the process: jose caches the fetched keys,
83
+ * refetches on an unknown `kid` (with a cooldown) and when they go stale, so a set created per
84
+ * call would refetch the keys for every id token.
85
+ */
86
+ const jwkSets = /* @__PURE__ */ new Map();
87
+ function remoteJWKSet(jwkSetUri) {
88
+ let jwks = jwkSets.get(jwkSetUri);
89
+ if (!jwks) {
90
+ jwks = createRemoteJWKSet(new URL(jwkSetUri));
91
+ jwkSets.set(jwkSetUri, jwks);
92
+ }
93
+ return jwks;
94
+ }
81
95
  async function verifyIdToken(idToken, options) {
82
96
  const { jwkSetUri, issuer, audience } = options;
83
97
  try {
84
- const jwks = createRemoteJWKSet(new URL(jwkSetUri));
98
+ const jwks = remoteJWKSet(jwkSetUri);
85
99
  const { payload } = await jwtVerify(idToken, jwks, {
86
100
  issuer,
87
101
  audience
@@ -89,7 +103,7 @@ async function verifyIdToken(idToken, options) {
89
103
  return payload;
90
104
  } catch (error) {
91
105
  console.error("Failed to verify id_token", error);
92
- throw new OAuth2Error(400, "invalid_request", "Failed to verify id_token");
106
+ throw new OAuth2Error(400, "invalid_grant", "Failed to verify id_token");
93
107
  }
94
108
  }
95
109
  export { createAuthorizationUri, exchangeAuthorizationCode, refreshAccessToken, revokeToken, verifyIdToken };
@@ -1 +1 @@
1
- {"version":3,"file":"common.mjs","names":[],"sources":["../../../src/oauth2/provider/common.ts"],"sourcesContent":["import { createRemoteJWKSet, jwtVerify } from 'jose';\nimport { OAuth2Error } from '../error';\nimport type { ExchangeCodeParams, PkceParameters, RefreshTokenParams } from '../types';\n\nexport function createAuthorizationUri(options: {\n state: string;\n scope: string[];\n clientId: string;\n redirectUri: string;\n authorizationUri: string;\n pkce?: Omit<PkceParameters, 'code_verifier'>;\n}) {\n const url = new URL(options.authorizationUri);\n url.searchParams.append('response_type', 'code');\n url.searchParams.append('client_id', options.clientId);\n url.searchParams.append('state', options.state);\n url.searchParams.append('scope', options.scope.join(' '));\n url.searchParams.append('redirect_uri', options.redirectUri);\n if (options.pkce) {\n url.searchParams.append('code_challenge_method', options.pkce.code_challenge_method);\n url.searchParams.append('code_challenge', options.pkce.code_challenge);\n }\n return url;\n}\n\nexport async function exchangeAuthorizationCode(\n params: ExchangeCodeParams & {\n tokenUri: string;\n authentication?: 'basic' | 'post';\n /** Extra request headers some providers require, e.g. GitHub's `User-Agent`. */\n headers?: Record<string, string>;\n }\n) {\n const body = new URLSearchParams();\n body.append('code', params.code);\n body.append('redirect_uri', params.redirectUri);\n body.append('grant_type', 'authorization_code');\n if (params.pkce) body.append('code_verifier', params.pkce.code_verifier);\n\n const headers: Record<string, string> = {\n ...params.headers,\n Accept: 'application/json',\n 'Content-Type': 'application/x-www-form-urlencoded',\n };\n if (params.authentication === 'basic') {\n const token = Buffer.from(`${params.clientId}:${params.clientSecret ?? ''}`).toString('base64');\n headers.Authorization = `Basic ${token}`;\n } else {\n body.append('client_id', params.clientId);\n // Public clients (Google's installed-app clients, PKCE-only clients) have no secret.\n if (params.clientSecret) body.append('client_secret', params.clientSecret);\n }\n\n return fetch(params.tokenUri, { method: 'POST', headers, body });\n}\n\nexport async function refreshAccessToken(\n params: RefreshTokenParams & {\n tokenUri: string;\n authentication?: 'basic' | 'post';\n }\n) {\n const body = new URLSearchParams();\n body.append('grant_type', 'refresh_token');\n body.append('refresh_token', params.refreshToken);\n\n const headers: Record<string, string> = {\n Accept: 'application/json',\n 'Content-Type': 'application/x-www-form-urlencoded',\n };\n\n if (params.authentication === 'basic') {\n const token = Buffer.from(`${params.clientId}:${params.clientSecret ?? ''}`).toString('base64');\n headers.Authorization = `Basic ${token}`;\n } else {\n body.append('client_id', params.clientId);\n if (params.clientSecret) body.append('client_secret', params.clientSecret);\n }\n\n return fetch(params.tokenUri, { method: 'POST', headers, body });\n}\n\ninterface RevokeTokenParams {\n token: string;\n clientId: string;\n clientSecret?: string;\n tokenRevokeUri: string;\n authentication?: 'basic' | 'post';\n}\n\nexport async function revokeToken(params: RevokeTokenParams) {\n const body = new URLSearchParams();\n body.append('token', params.token);\n const headers: Record<string, string> = {\n Accept: 'application/json',\n 'Content-Type': 'application/x-www-form-urlencoded',\n };\n\n if (params.authentication === 'basic') {\n const token = Buffer.from(`${params.clientId}:${params.clientSecret ?? ''}`).toString('base64');\n headers.Authorization = `Basic ${token}`;\n } else {\n body.append('client_id', params.clientId);\n if (params.clientSecret) body.append('client_secret', params.clientSecret);\n }\n\n const response = await fetch(params.tokenRevokeUri, { method: 'POST', headers, body });\n if (!response.ok) {\n const error = await response.json();\n console.error('Refresh token error:', error);\n throw new OAuth2Error(response.status, 'invalid_request', 'Failed to revoke token');\n }\n}\n\nexport interface VerifyIdTokenOptions {\n jwkSetUri: string;\n /** The `iss` values the provider signs with; anything else is refused. */\n issuer: string | string[];\n /**\n * The client the token must be issued to. An id token proves who the user is only to the client\n * it names in `aud`: any other app on the same identity provider can obtain a validly signed one\n * for the same user, so a token for a foreign client must never sign anyone in here.\n */\n audience: string;\n}\n\nexport async function verifyIdToken<T>(idToken: string, options: VerifyIdTokenOptions) {\n const { jwkSetUri, issuer, audience } = options;\n try {\n const jwks = createRemoteJWKSet(new URL(jwkSetUri));\n const { payload } = await jwtVerify(idToken, jwks, { issuer, audience });\n return payload as T;\n } catch (error) {\n console.error('Failed to verify id_token', error);\n throw new OAuth2Error(400, 'invalid_request', 'Failed to verify id_token');\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"common.mjs","names":[],"sources":["../../../src/oauth2/provider/common.ts"],"sourcesContent":["import { createRemoteJWKSet, jwtVerify } from 'jose';\nimport { OAuth2Error } from '../error';\nimport type { ExchangeCodeParams, PkceParameters, RefreshTokenParams } from '../types';\n\nexport function createAuthorizationUri(options: {\n state: string;\n scope: string[];\n clientId: string;\n redirectUri: string;\n authorizationUri: string;\n pkce?: Omit<PkceParameters, 'code_verifier'>;\n}) {\n const url = new URL(options.authorizationUri);\n url.searchParams.append('response_type', 'code');\n url.searchParams.append('client_id', options.clientId);\n url.searchParams.append('state', options.state);\n url.searchParams.append('scope', options.scope.join(' '));\n url.searchParams.append('redirect_uri', options.redirectUri);\n if (options.pkce) {\n url.searchParams.append('code_challenge_method', options.pkce.code_challenge_method);\n url.searchParams.append('code_challenge', options.pkce.code_challenge);\n }\n return url;\n}\n\nexport async function exchangeAuthorizationCode(\n params: ExchangeCodeParams & {\n tokenUri: string;\n authentication?: 'basic' | 'post';\n /** Extra request headers some providers require, e.g. GitHub's `User-Agent`. */\n headers?: Record<string, string>;\n }\n) {\n const body = new URLSearchParams();\n body.append('code', params.code);\n body.append('redirect_uri', params.redirectUri);\n body.append('grant_type', 'authorization_code');\n if (params.pkce) body.append('code_verifier', params.pkce.code_verifier);\n\n const headers: Record<string, string> = {\n ...params.headers,\n Accept: 'application/json',\n 'Content-Type': 'application/x-www-form-urlencoded',\n };\n if (params.authentication === 'basic') {\n const token = Buffer.from(`${params.clientId}:${params.clientSecret ?? ''}`).toString('base64');\n headers.Authorization = `Basic ${token}`;\n } else {\n body.append('client_id', params.clientId);\n // Public clients (Google's installed-app clients, PKCE-only clients) have no secret.\n if (params.clientSecret) body.append('client_secret', params.clientSecret);\n }\n\n return fetch(params.tokenUri, { method: 'POST', headers, body });\n}\n\nexport async function refreshAccessToken(\n params: RefreshTokenParams & {\n tokenUri: string;\n authentication?: 'basic' | 'post';\n }\n) {\n const body = new URLSearchParams();\n body.append('grant_type', 'refresh_token');\n body.append('refresh_token', params.refreshToken);\n\n const headers: Record<string, string> = {\n Accept: 'application/json',\n 'Content-Type': 'application/x-www-form-urlencoded',\n };\n\n if (params.authentication === 'basic') {\n const token = Buffer.from(`${params.clientId}:${params.clientSecret ?? ''}`).toString('base64');\n headers.Authorization = `Basic ${token}`;\n } else {\n body.append('client_id', params.clientId);\n if (params.clientSecret) body.append('client_secret', params.clientSecret);\n }\n\n return fetch(params.tokenUri, { method: 'POST', headers, body });\n}\n\ninterface RevokeTokenParams {\n token: string;\n clientId: string;\n clientSecret?: string;\n tokenRevokeUri: string;\n authentication?: 'basic' | 'post';\n}\n\nexport async function revokeToken(params: RevokeTokenParams) {\n const body = new URLSearchParams();\n body.append('token', params.token);\n const headers: Record<string, string> = {\n Accept: 'application/json',\n 'Content-Type': 'application/x-www-form-urlencoded',\n };\n\n if (params.authentication === 'basic') {\n const token = Buffer.from(`${params.clientId}:${params.clientSecret ?? ''}`).toString('base64');\n headers.Authorization = `Basic ${token}`;\n } else {\n body.append('client_id', params.clientId);\n if (params.clientSecret) body.append('client_secret', params.clientSecret);\n }\n\n const response = await fetch(params.tokenRevokeUri, { method: 'POST', headers, body });\n if (!response.ok) {\n const error = await response.json();\n console.error('Revoke token error:', error);\n throw new OAuth2Error(response.status, 'invalid_request', 'Failed to revoke token');\n }\n}\n\nexport interface VerifyIdTokenOptions {\n jwkSetUri: string;\n /** The `iss` values the provider signs with; anything else is refused. */\n issuer: string | string[];\n /**\n * The client the token must be issued to. An id token proves who the user is only to the client\n * it names in `aud`: any other app on the same identity provider can obtain a validly signed one\n * for the same user, so a token for a foreign client must never sign anyone in here.\n */\n audience: string;\n}\n\n/**\n * One key set per JWKS endpoint for the life of the process: jose caches the fetched keys,\n * refetches on an unknown `kid` (with a cooldown) and when they go stale, so a set created per\n * call would refetch the keys for every id token.\n */\nconst jwkSets = new Map<string, ReturnType<typeof createRemoteJWKSet>>();\n\nfunction remoteJWKSet(jwkSetUri: string) {\n let jwks = jwkSets.get(jwkSetUri);\n if (!jwks) {\n jwks = createRemoteJWKSet(new URL(jwkSetUri));\n jwkSets.set(jwkSetUri, jwks);\n }\n return jwks;\n}\n\nexport async function verifyIdToken<T>(idToken: string, options: VerifyIdTokenOptions) {\n const { jwkSetUri, issuer, audience } = options;\n try {\n const jwks = remoteJWKSet(jwkSetUri);\n const { payload } = await jwtVerify(idToken, jwks, { issuer, audience });\n return payload as T;\n } catch (error) {\n console.error('Failed to verify id_token', error);\n // The token is the grant here: one for another audience or issuer is an invalid grant, not a\n // malformed request.\n throw new OAuth2Error(400, 'invalid_grant', 'Failed to verify id_token');\n }\n}\n"],"mappings":"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"}
@@ -53,8 +53,7 @@ function createFacebookProvider() {
53
53
  sub: data.sub,
54
54
  name: data.name,
55
55
  picture: data.picture,
56
- email: data.email,
57
- email_verified: true
56
+ email: data.email
58
57
  }
59
58
  };
60
59
  }
@@ -108,8 +107,7 @@ async function fetchUserInfo(userInfoUri, accessToken, appSecretProof) {
108
107
  sub: data.id,
109
108
  name: data.name,
110
109
  email: data.email,
111
- picture: data.picture.data.url,
112
- email_verified: data.email_verified
110
+ picture: data.picture.data.url
113
111
  }
114
112
  };
115
113
  }
@@ -1 +1 @@
1
- {"version":3,"file":"facebook.cjs","names":["createAuthorizationUri","exchangeAuthorizationCode","OAuth2Error","verifyIdToken","createHmac"],"sources":["../../../src/oauth2/provider/facebook.ts"],"sourcesContent":["import { createHmac } from 'node:crypto';\nimport { invariant } from '@shware/utils';\nimport { OAuth2Error } from '../error';\nimport type { LoginOAuth2NativeParams, OAuth2Token, Provider, UserInfo } from '../types';\nimport { createAuthorizationUri, exchangeAuthorizationCode, verifyIdToken } from './common';\n\n/**\n * `iss` of Limited Login id tokens, per https://limited.facebook.com/.well-known/openid-configuration/\n * (their `aud` is the app id).\n */\nconst FACEBOOK_ISSUER = 'https://www.facebook.com';\n\n/**\n * ref: https://developers.facebook.com/docs/facebook-login/guides/advanced/manual-flow/\n * ref: https://developers.facebook.com/tools/explorer\n * */\nexport function createFacebookProvider(): Provider {\n return {\n authorizationUri: 'https://www.facebook.com/v21.0/dialog/oauth',\n tokenUri: 'https://graph.facebook.com/v19.0/oauth/access_token',\n userInfoUri: 'https://graph.facebook.com/me',\n jwkSetUri: 'https://limited.facebook.com/.well-known/oauth/openid/jwks/',\n userNameAttribute: 'id',\n defaultScope: ['profile', 'email'],\n createAuthorizationUri({ pkce: _, ...params }) {\n return createAuthorizationUri({\n ...params,\n scope: params.scope ?? this.defaultScope,\n authorizationUri: this.authorizationUri,\n });\n },\n async exchangeAuthorizationCode({ pkce: _, ...params }) {\n const response = await exchangeAuthorizationCode({ ...params, tokenUri: this.tokenUri });\n if (!response.ok) {\n const { error } = (await response.json()) as FacebookErrorResponse;\n throw new OAuth2Error(response.status, 'invalid_request', error.message);\n }\n return (await response.json()) as FacebookToken;\n },\n async getUserInfo({ id_token, access_token }, { clientId }) {\n invariant(this.jwkSetUri, 'jwkSetUri is required');\n if (id_token) {\n const data = await verifyIdToken<FacebookDecodedIdToken>(id_token, {\n jwkSetUri: this.jwkSetUri,\n issuer: FACEBOOK_ISSUER,\n audience: clientId,\n });\n return {\n data,\n claims: {\n sub: data.sub,\n name: data.name,\n picture: data.picture,\n email: data.email,\n email_verified: true,\n },\n };\n }\n invariant(access_token, 'access_token is required');\n invariant(this.userInfoUri, 'userInfoUri is required');\n return fetchUserInfo(this.userInfoUri, access_token);\n },\n async loginOAuth2Native({ clientId, clientSecret, credentials }: LoginOAuth2NativeParams) {\n const { id_token, access_token } = credentials;\n let userInfo: UserInfo;\n if (id_token) {\n // Limited Login: the id token's `aud` must be this app.\n userInfo = await this.getUserInfo(\n { token_type: 'bearer', access_token: '', id_token },\n {\n clientId,\n }\n );\n } else if (access_token) {\n // The Graph API serves any app's user access token, so `/me` alone would accept a token a\n // foreign app obtained for the same user. With `appsecret_proof` Facebook refuses tokens\n // not issued to the app whose secret signed the proof, binding the token to this client.\n if (!clientSecret) {\n throw new OAuth2Error(400, 'invalid_client', 'access_token login needs the app secret');\n }\n invariant(this.userInfoUri, 'userInfoUri is required');\n const proof = createHmac('sha256', clientSecret).update(access_token).digest('hex');\n userInfo = await fetchUserInfo(this.userInfoUri, access_token, proof);\n } else {\n throw new OAuth2Error(400, 'invalid_request', 'id_token or access_token is required');\n }\n const token: OAuth2Token = {\n token_type: 'bearer',\n access_token: access_token ?? '',\n id_token,\n };\n return { token, userInfo };\n },\n };\n}\n\nexport const facebook = createFacebookProvider();\n\nasync function fetchUserInfo(\n userInfoUri: string,\n accessToken: string,\n appSecretProof?: string\n): Promise<UserInfo<FacebookUserInfo>> {\n const url = new URL(userInfoUri);\n const fields = ['id', 'name', 'email', 'picture.width(320).height(320)'];\n url.searchParams.append('access_token', accessToken);\n url.searchParams.append('fields', fields.join(','));\n if (appSecretProof) url.searchParams.append('appsecret_proof', appSecretProof);\n const headers = { Accept: 'application/json' };\n const response = await fetch(url.href, { headers });\n if (!response.ok) {\n throw new OAuth2Error(response.status, 'invalid_request', 'Failed to fetch user info');\n }\n const data = (await response.json()) as FacebookUserInfo;\n return {\n data,\n claims: {\n sub: data.id,\n name: data.name,\n email: data.email,\n picture: data.picture.data.url,\n email_verified: data.email_verified,\n },\n };\n}\n\nexport interface FacebookDecodedIdToken {\n sub: string;\n name: string;\n email: string;\n picture: string;\n nonce?: string;\n}\n\nexport interface FacebookUserInfo {\n id: string;\n name: string;\n email: string;\n email_verified: boolean;\n picture: {\n data: {\n url: string;\n width: number;\n height: number;\n is_silhouette: boolean;\n };\n };\n}\n\nexport interface FacebookToken extends OAuth2Token {\n access_token: string;\n token_type: 'bearer';\n expires_in: number;\n id_token?: string;\n}\n\nexport type FacebookAppCredential =\n | { state: string; id_token: string } // platform=ios and tracking=limited\n | { state: string; access_token: string }; // tracking=enabled\n\ninterface FacebookErrorResponse {\n error: {\n message: string;\n type: 'OAuthException';\n code: number;\n error_subcode: number;\n fbtrace_id: string;\n };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"facebook.cjs","names":["createAuthorizationUri","exchangeAuthorizationCode","OAuth2Error","verifyIdToken","createHmac"],"sources":["../../../src/oauth2/provider/facebook.ts"],"sourcesContent":["import { createHmac } from 'node:crypto';\nimport { invariant } from '@shware/utils';\nimport { OAuth2Error } from '../error';\nimport type { LoginOAuth2NativeParams, OAuth2Token, Provider, UserInfo } from '../types';\nimport { createAuthorizationUri, exchangeAuthorizationCode, verifyIdToken } from './common';\n\n/**\n * `iss` of Limited Login id tokens, per https://limited.facebook.com/.well-known/openid-configuration/\n * (their `aud` is the app id).\n */\nconst FACEBOOK_ISSUER = 'https://www.facebook.com';\n\n/**\n * ref: https://developers.facebook.com/docs/facebook-login/guides/advanced/manual-flow/\n * ref: https://developers.facebook.com/tools/explorer\n * */\nexport function createFacebookProvider(): Provider {\n return {\n authorizationUri: 'https://www.facebook.com/v21.0/dialog/oauth',\n tokenUri: 'https://graph.facebook.com/v19.0/oauth/access_token',\n userInfoUri: 'https://graph.facebook.com/me',\n jwkSetUri: 'https://limited.facebook.com/.well-known/oauth/openid/jwks/',\n userNameAttribute: 'id',\n defaultScope: ['profile', 'email'],\n createAuthorizationUri({ pkce: _, ...params }) {\n return createAuthorizationUri({\n ...params,\n scope: params.scope ?? this.defaultScope,\n authorizationUri: this.authorizationUri,\n });\n },\n async exchangeAuthorizationCode({ pkce: _, ...params }) {\n const response = await exchangeAuthorizationCode({ ...params, tokenUri: this.tokenUri });\n if (!response.ok) {\n const { error } = (await response.json()) as FacebookErrorResponse;\n throw new OAuth2Error(response.status, 'invalid_request', error.message);\n }\n return (await response.json()) as FacebookToken;\n },\n async getUserInfo({ id_token, access_token }, { clientId }) {\n invariant(this.jwkSetUri, 'jwkSetUri is required');\n if (id_token) {\n const data = await verifyIdToken<FacebookDecodedIdToken>(id_token, {\n jwkSetUri: this.jwkSetUri,\n issuer: FACEBOOK_ISSUER,\n audience: clientId,\n });\n return {\n data,\n claims: {\n sub: data.sub,\n name: data.name,\n picture: data.picture,\n email: data.email,\n // Facebook does not say whether the address is verified: left unset, so a host that\n // trusts only `email_verified === true` treats it as unverified.\n },\n };\n }\n invariant(access_token, 'access_token is required');\n invariant(this.userInfoUri, 'userInfoUri is required');\n return fetchUserInfo(this.userInfoUri, access_token);\n },\n async loginOAuth2Native({ clientId, clientSecret, credentials }: LoginOAuth2NativeParams) {\n const { id_token, access_token } = credentials;\n let userInfo: UserInfo;\n if (id_token) {\n // Limited Login: the id token's `aud` must be this app.\n userInfo = await this.getUserInfo(\n { token_type: 'bearer', access_token: '', id_token },\n {\n clientId,\n }\n );\n } else if (access_token) {\n // The Graph API serves any app's user access token, so `/me` alone would accept a token a\n // foreign app obtained for the same user. With `appsecret_proof` Facebook refuses tokens\n // not issued to the app whose secret signed the proof, binding the token to this client.\n if (!clientSecret) {\n throw new OAuth2Error(400, 'invalid_client', 'access_token login needs the app secret');\n }\n invariant(this.userInfoUri, 'userInfoUri is required');\n const proof = createHmac('sha256', clientSecret).update(access_token).digest('hex');\n userInfo = await fetchUserInfo(this.userInfoUri, access_token, proof);\n } else {\n throw new OAuth2Error(400, 'invalid_request', 'id_token or access_token is required');\n }\n const token: OAuth2Token = {\n token_type: 'bearer',\n access_token: access_token ?? '',\n id_token,\n };\n return { token, userInfo };\n },\n };\n}\n\nexport const facebook = createFacebookProvider();\n\nasync function fetchUserInfo(\n userInfoUri: string,\n accessToken: string,\n appSecretProof?: string\n): Promise<UserInfo<FacebookUserInfo>> {\n const url = new URL(userInfoUri);\n const fields = ['id', 'name', 'email', 'picture.width(320).height(320)'];\n url.searchParams.append('access_token', accessToken);\n url.searchParams.append('fields', fields.join(','));\n if (appSecretProof) url.searchParams.append('appsecret_proof', appSecretProof);\n const headers = { Accept: 'application/json' };\n const response = await fetch(url.href, { headers });\n if (!response.ok) {\n throw new OAuth2Error(response.status, 'invalid_request', 'Failed to fetch user info');\n }\n const data = (await response.json()) as FacebookUserInfo;\n return {\n data,\n claims: {\n sub: data.id,\n name: data.name,\n email: data.email,\n picture: data.picture.data.url,\n // Not stated by the Graph API either; see the Limited Login path above.\n },\n };\n}\n\nexport interface FacebookDecodedIdToken {\n sub: string;\n name: string;\n email: string;\n picture: string;\n nonce?: string;\n}\n\nexport interface FacebookUserInfo {\n id: string;\n name: string;\n email: string;\n picture: {\n data: {\n url: string;\n width: number;\n height: number;\n is_silhouette: boolean;\n };\n };\n}\n\nexport interface FacebookToken extends OAuth2Token {\n access_token: string;\n token_type: 'bearer';\n expires_in: number;\n id_token?: string;\n}\n\nexport type FacebookAppCredential =\n | { state: string; id_token: string } // platform=ios and tracking=limited\n | { state: string; access_token: string }; // tracking=enabled\n\ninterface FacebookErrorResponse {\n error: {\n message: string;\n type: 'OAuthException';\n code: number;\n error_subcode: number;\n fbtrace_id: string;\n };\n}\n"],"mappings":"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"}
@@ -16,7 +16,6 @@ export interface FacebookUserInfo {
16
16
  id: string;
17
17
  name: string;
18
18
  email: string;
19
- email_verified: boolean;
20
19
  picture: {
21
20
  data: {
22
21
  url: string;
@@ -1 +1 @@
1
- {"version":3,"file":"facebook.d.cts","names":[],"sources":["../../../src/oauth2/provider/facebook.ts"],"mappings":";;;;;wBAgBgB,0BAA0B;qBAgF7B,UAAQ;iBA8BJ;EACf;EACA;EACA;EACA;EACA;;iBAGe;EACf;EACA;EACA;EACA;EACA;IACE;MACE;MACA;MACA;MACA;;;;iBAKW,sBAAsB;EACrC;EACA;EACA;EACA;;YAGU;EACN;EAAe;;EACf;EAAe"}
1
+ {"version":3,"file":"facebook.d.cts","names":[],"sources":["../../../src/oauth2/provider/facebook.ts"],"mappings":";;;;;wBAgBgB,0BAA0B;qBAiF7B,UAAQ;iBA8BJ;EACf;EACA;EACA;EACA;EACA;;iBAGe;EACf;EACA;EACA;EACA;IACE;MACE;MACA;MACA;MACA;;;;iBAKW,sBAAsB;EACrC;EACA;EACA;EACA;;YAGU;EACN;EAAe;;EACf;EAAe"}
@@ -16,7 +16,6 @@ export interface FacebookUserInfo {
16
16
  id: string;
17
17
  name: string;
18
18
  email: string;
19
- email_verified: boolean;
20
19
  picture: {
21
20
  data: {
22
21
  url: string;
@@ -1 +1 @@
1
- {"version":3,"file":"facebook.d.mts","names":[],"sources":["../../../src/oauth2/provider/facebook.ts"],"mappings":";;;;;wBAgBgB,0BAA0B;qBAgF7B,UAAQ;iBA8BJ;EACf;EACA;EACA;EACA;EACA;;iBAGe;EACf;EACA;EACA;EACA;EACA;IACE;MACE;MACA;MACA;MACA;;;;iBAKW,sBAAsB;EACrC;EACA;EACA;EACA;;YAGU;EACN;EAAe;;EACf;EAAe"}
1
+ {"version":3,"file":"facebook.d.mts","names":[],"sources":["../../../src/oauth2/provider/facebook.ts"],"mappings":";;;;;wBAgBgB,0BAA0B;qBAiF7B,UAAQ;iBA8BJ;EACf;EACA;EACA;EACA;EACA;;iBAGe;EACf;EACA;EACA;EACA;IACE;MACE;MACA;MACA;MACA;;;;iBAKW,sBAAsB;EACrC;EACA;EACA;EACA;;YAGU;EACN;EAAe;;EACf;EAAe"}