@shad-claiborne/hono-middleware-oidc 1.0.9 → 1.1.0

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/README.md CHANGED
@@ -15,15 +15,24 @@
15
15
  ```
16
16
  ### Usage
17
17
  ```ts
18
- app.use('*', except('/auth/callback', withIdentity));
18
+ import {addIdentity, receiveAuth, handleFlow} from '@shad-claiborne/hono-middleware-oidc'
19
19
 
20
- app.use('/auth/callback', forAuthorization);
20
+ ...
21
21
 
22
+ // Add the identity claims to the request for all routes except the redirect URI
23
+ app.use('*', except('/auth/callback', addIdentity));
24
+
25
+ // The endpoint to which the authorization server provides the user's authorization
26
+ app.use('/auth/callback', receiveAuth);
27
+
28
+ // Send the browser to this endpoint to begin the authorization flow
29
+ // Note this endpoint assumes "addIdentity" precedes it
30
+ app.use('/login', handleFlow);
31
+
32
+ // Example ajax endpoint for getting the identity claims
22
33
  app.get('/async/api/identity', async (c) => {
23
34
  return c.json(c.get('identity'));
24
35
  });
25
36
 
26
- app.get('/', async (c) => {
27
- return c.text('hello world');
28
- });
37
+ ...
29
38
  ```
package/dist/index.d.ts CHANGED
@@ -1,4 +1,22 @@
1
1
  import { MiddlewareHandler } from "hono";
2
- export declare const withIdentity: MiddlewareHandler;
3
- export declare const forAuthorization: MiddlewareHandler;
2
+ /**
3
+ * handleFlow
4
+ * @param c
5
+ * @param next
6
+ * @returns
7
+ */
8
+ export declare const handleFlow: MiddlewareHandler;
9
+ /**
10
+ * addIdentity
11
+ * @param c
12
+ * @param next
13
+ * @returns
14
+ */
15
+ export declare const addIdentity: MiddlewareHandler;
16
+ /**
17
+ * receiveAuth
18
+ * @param c
19
+ * @returns
20
+ */
21
+ export declare const receiveAuth: MiddlewareHandler;
4
22
  //# sourceMappingURL=index.d.ts.map
package/dist/index.js CHANGED
@@ -2,8 +2,64 @@ import { deleteCookie, getSignedCookie, setSignedCookie } from "hono/cookie";
2
2
  import { createIdentityProvider, } from "@shad-claiborne/basic-oidc";
3
3
  import randomstring from "randomstring";
4
4
  import { env } from "hono/adapter";
5
- export const withIdentity = async (c, next) => {
6
- const { HONO_OIDC_ISSUER, HONO_OIDC_CLIENT_ID, HONO_OIDC_CLIENT_SECRET, HONO_OIDC_REDIRECT_URI, HONO_OIDC_COOKIE_SECRET, HONO_OIDC_ACCESS_TOKEN_COOKIE, HONO_OIDC_REFRESH_TOKEN_COOKIE, HONO_OIDC_ID_TOKEN_COOKIE, HONO_OIDC_CODE_VERIFIER_COOKIE, } = env(c);
5
+ /**
6
+ * activateToken
7
+ * @param c
8
+ * @param tokenRes
9
+ */
10
+ const activateToken = async (c, provider, tokenResponse) => {
11
+ const { HONO_OIDC_COOKIE_SECRET, HONO_OIDC_ACCESS_TOKEN_COOKIE, HONO_OIDC_REFRESH_TOKEN_COOKIE, HONO_OIDC_ID_TOKEN_COOKIE, } = env(c);
12
+ if (tokenResponse.access_token) {
13
+ await setSignedCookie(c, HONO_OIDC_ACCESS_TOKEN_COOKIE, tokenResponse.access_token, HONO_OIDC_COOKIE_SECRET, { httpOnly: true, secure: true, sameSite: 'Lax', maxAge: tokenResponse.expires_in });
14
+ }
15
+ if (tokenResponse.refresh_token) {
16
+ const maxAge = tokenResponse.refresh_token_expires_in ?? (24 * 60 * 60);
17
+ await setSignedCookie(c, HONO_OIDC_REFRESH_TOKEN_COOKIE, tokenResponse.refresh_token, HONO_OIDC_COOKIE_SECRET, { httpOnly: true, secure: true, sameSite: 'Lax', maxAge });
18
+ }
19
+ if (tokenResponse.id_token) {
20
+ const idToken = await provider.decodeIdentityToken(tokenResponse.id_token);
21
+ const maxAge = idToken.exp - Math.floor(Date.now() / 1000);
22
+ await setSignedCookie(c, HONO_OIDC_ID_TOKEN_COOKIE, tokenResponse.id_token, HONO_OIDC_COOKIE_SECRET, { httpOnly: true, secure: true, sameSite: 'Lax', maxAge });
23
+ }
24
+ };
25
+ /**
26
+ * handleFlow
27
+ * @param c
28
+ * @param next
29
+ * @returns
30
+ */
31
+ export const handleFlow = async (c, next) => {
32
+ const { HONO_OIDC_ISSUER, HONO_OIDC_CLIENT_ID, HONO_OIDC_CLIENT_SECRET, HONO_OIDC_REDIRECT_URI, HONO_OIDC_COOKIE_SECRET, HONO_OIDC_CODE_VERIFIER_COOKIE, } = env(c);
33
+ const provider = await createIdentityProvider(HONO_OIDC_ISSUER);
34
+ const client = provider.createClient(HONO_OIDC_CLIENT_ID, HONO_OIDC_CLIENT_SECRET);
35
+ let id = c.get('identity');
36
+ if (!id) {
37
+ const stateId = randomstring.generate(5);
38
+ const state = { originUrl: c.get('originUrl') || c.req.url };
39
+ await setSignedCookie(c, `_authstate-${stateId}`, JSON.stringify(state), HONO_OIDC_COOKIE_SECRET, { httpOnly: true, secure: true, sameSite: 'Lax' });
40
+ const codeVerifier = randomstring.generate(16);
41
+ await setSignedCookie(c, HONO_OIDC_CODE_VERIFIER_COOKIE, codeVerifier, HONO_OIDC_COOKIE_SECRET, { httpOnly: true, secure: true, sameSite: 'Lax' });
42
+ const authRequest = client
43
+ .newAuthorizationRequest()
44
+ .setRedirectUri(HONO_OIDC_REDIRECT_URI)
45
+ .setResponseMode("query")
46
+ .setResponseType("code id_token")
47
+ .setScope(["profile"])
48
+ .setCodeChallenge(codeVerifier)
49
+ .setState(stateId);
50
+ const authRequestURL = authRequest.toURL();
51
+ return c.redirect(authRequestURL.toString());
52
+ }
53
+ await next();
54
+ };
55
+ /**
56
+ * addIdentity
57
+ * @param c
58
+ * @param next
59
+ * @returns
60
+ */
61
+ export const addIdentity = async (c, next) => {
62
+ const { HONO_OIDC_ISSUER, HONO_OIDC_CLIENT_ID, HONO_OIDC_CLIENT_SECRET, HONO_OIDC_COOKIE_SECRET, HONO_OIDC_ACCESS_TOKEN_COOKIE, HONO_OIDC_REFRESH_TOKEN_COOKIE, HONO_OIDC_ID_TOKEN_COOKIE, } = env(c);
7
63
  const provider = await createIdentityProvider(HONO_OIDC_ISSUER);
8
64
  const client = provider.createClient(HONO_OIDC_CLIENT_ID, HONO_OIDC_CLIENT_SECRET);
9
65
  const tokenSet = {
@@ -16,48 +72,30 @@ export const withIdentity = async (c, next) => {
16
72
  id = await provider.getIdentity(tokenSet);
17
73
  }
18
74
  catch (err) {
19
- id = null;
75
+ console.error(err);
20
76
  }
21
- if (id === null) {
77
+ if (!id) {
22
78
  try {
23
79
  const tokenResponse = await client.refreshAccess(tokenSet);
24
80
  id = await provider.getIdentity(tokenResponse);
25
- if (tokenResponse.access_token) {
26
- await setSignedCookie(c, HONO_OIDC_ACCESS_TOKEN_COOKIE, tokenResponse.access_token, HONO_OIDC_COOKIE_SECRET, { httpOnly: true, secure: true, sameSite: 'Lax' });
27
- }
28
- if (tokenResponse.refresh_token) {
29
- const maxAge = tokenResponse.refresh_token_expires_in ?? (24 * 60 * 60);
30
- await setSignedCookie(c, HONO_OIDC_REFRESH_TOKEN_COOKIE, tokenResponse.refresh_token, HONO_OIDC_COOKIE_SECRET, { httpOnly: true, secure: true, sameSite: 'Lax', maxAge });
31
- }
32
- if (tokenResponse.id_token) {
33
- const idToken = await provider.decodeIdentityToken(tokenResponse.id_token);
34
- const maxAge = idToken.exp - Math.floor(Date.now() / 1000);
35
- await setSignedCookie(c, HONO_OIDC_ID_TOKEN_COOKIE, tokenResponse.id_token, HONO_OIDC_COOKIE_SECRET, { httpOnly: true, secure: true, sameSite: 'Lax', maxAge });
36
- }
81
+ await activateToken(c, provider, tokenResponse);
37
82
  }
38
83
  catch (err) {
39
- const stateId = randomstring.generate(5);
40
- const state = { originUrl: c.get('originUrl') || c.req.url };
41
- await setSignedCookie(c, `_authstate-${stateId}`, JSON.stringify(state), HONO_OIDC_COOKIE_SECRET, { httpOnly: true, secure: true, sameSite: 'Lax' });
42
- const codeVerifier = randomstring.generate(16);
43
- await setSignedCookie(c, HONO_OIDC_CODE_VERIFIER_COOKIE, codeVerifier, HONO_OIDC_COOKIE_SECRET, { httpOnly: true, secure: true, sameSite: 'Lax' });
44
- const authRequest = client
45
- .newAuthorizationRequest()
46
- .setRedirectUri(HONO_OIDC_REDIRECT_URI)
47
- .setResponseMode("query")
48
- .setResponseType("code id_token")
49
- .setScope(["profile"])
50
- .setCodeChallenge(codeVerifier)
51
- .setState(stateId);
52
- const authRequestURL = authRequest.toURL();
53
- return c.redirect(authRequestURL.toString());
84
+ console.error(err);
54
85
  }
55
86
  }
56
- c.set("identity", id);
87
+ if (id) {
88
+ c.set("identity", id);
89
+ }
57
90
  await next();
58
91
  };
59
- export const forAuthorization = async (c) => {
60
- const { HONO_OIDC_ISSUER, HONO_OIDC_CLIENT_ID, HONO_OIDC_CLIENT_SECRET, HONO_OIDC_REDIRECT_URI, HONO_OIDC_COOKIE_SECRET, HONO_OIDC_ACCESS_TOKEN_COOKIE, HONO_OIDC_REFRESH_TOKEN_COOKIE, HONO_OIDC_ID_TOKEN_COOKIE, HONO_OIDC_CODE_VERIFIER_COOKIE, } = env(c);
92
+ /**
93
+ * receiveAuth
94
+ * @param c
95
+ * @returns
96
+ */
97
+ export const receiveAuth = async (c) => {
98
+ const { HONO_OIDC_ISSUER, HONO_OIDC_CLIENT_ID, HONO_OIDC_CLIENT_SECRET, HONO_OIDC_REDIRECT_URI, HONO_OIDC_COOKIE_SECRET, HONO_OIDC_CODE_VERIFIER_COOKIE, } = env(c);
61
99
  const provider = await createIdentityProvider(HONO_OIDC_ISSUER);
62
100
  const client = provider.createClient(HONO_OIDC_CLIENT_ID, HONO_OIDC_CLIENT_SECRET);
63
101
  const requestURL = new URL(c.req.url), requestParams = requestURL.searchParams;
@@ -76,18 +114,7 @@ export const forAuthorization = async (c) => {
76
114
  if (codeVerifier === false || codeVerifier === undefined)
77
115
  throw new Error("code verifier cookie failed");
78
116
  const tokenResponse = await client.requestAccess(authResponse, { codeVerifier, redirectUri: HONO_OIDC_REDIRECT_URI });
79
- if (tokenResponse.access_token) {
80
- await setSignedCookie(c, HONO_OIDC_ACCESS_TOKEN_COOKIE, tokenResponse.access_token, HONO_OIDC_COOKIE_SECRET, { httpOnly: true, secure: true, sameSite: 'Lax', maxAge: tokenResponse.expires_in });
81
- }
82
- if (tokenResponse.refresh_token) {
83
- const maxAge = tokenResponse.refresh_token_expires_in ?? (24 * 60 * 60);
84
- await setSignedCookie(c, HONO_OIDC_REFRESH_TOKEN_COOKIE, tokenResponse.refresh_token, HONO_OIDC_COOKIE_SECRET, { httpOnly: true, secure: true, sameSite: 'Lax', maxAge });
85
- }
86
- if (tokenResponse.id_token) {
87
- const idToken = await provider.decodeIdentityToken(tokenResponse.id_token);
88
- const maxAge = idToken.exp - Math.floor(Date.now() / 1000);
89
- await setSignedCookie(c, HONO_OIDC_ID_TOKEN_COOKIE, tokenResponse.id_token, HONO_OIDC_COOKIE_SECRET, { httpOnly: true, secure: true, sameSite: 'Lax', maxAge });
90
- }
117
+ await activateToken(c, provider, tokenResponse);
91
118
  return c.redirect(state.originUrl);
92
119
  };
93
120
  //# sourceMappingURL=index.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shad-claiborne/hono-middleware-oidc",
3
- "version": "1.0.9",
3
+ "version": "1.1.0",
4
4
  "description": "OIDC middleware for Hono",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",