diff --git a/packages/sst/src/node/auth/adapter/oauth.ts b/packages/sst/src/node/auth/adapter/oauth.ts index cbfa8241b..60bcfde86 100644 --- a/packages/sst/src/node/auth/adapter/oauth.ts +++ b/packages/sst/src/node/auth/adapter/oauth.ts @@ -1,5 +1,5 @@ import { APIGatewayProxyStructuredResultV2 } from "aws-lambda"; -import { BaseClient, generators, Issuer, TokenSet } from "openid-client"; +import { BaseClient, ClientMetadata, generators, Issuer, TokenSet } from "openid-client"; import { useCookie, useDomainName, @@ -22,6 +22,10 @@ export interface OauthBasicConfig { */ scope: string; prompt?: string; + /** + * Additional auth client metadata + */ + clientMetadata?: Partial /** * onSuccess callback when the oauth flow is successful. Will provide tokenset */ @@ -48,6 +52,7 @@ export const OauthAdapter = /* @__PURE__ */ createAdapter( client_secret: config.clientSecret, redirect_uris: [callback], response_types: ["code"], + ...config.clientMetadata, }); if (step === "authorize" || step === "connect") { diff --git a/packages/sst/src/node/auth/adapter/openauth.ts b/packages/sst/src/node/auth/adapter/openauth.ts new file mode 100644 index 000000000..e2fd01eaf --- /dev/null +++ b/packages/sst/src/node/auth/adapter/openauth.ts @@ -0,0 +1,34 @@ +import { BaseClient, Issuer, TokenSet } from "openid-client"; +import { createDecoder } from 'fast-jwt'; +import { createAdapter } from "./adapter.js"; +import { OauthAdapter, OauthBasicConfig } from "./oauth.js"; +import type { APIGatewayProxyStructuredResultV2 } from "aws-lambda"; + +type OpenauthConfig = Omit & { + issuer: string; + onSuccess: (claims: any, tokenset: TokenSet, client: BaseClient) => Promise; +}; + +export const OpenauthAdapter = /* @__PURE__ */ createAdapter( + (config: OpenauthConfig) => { + return OauthAdapter({ + ...config, + issuer: new Issuer({ + issuer: config.issuer, + authorization_endpoint: config.issuer + "/authorize", + token_endpoint: config.issuer + "/token", + }), + clientSecret: "", + scope: "", + clientMetadata: { + token_endpoint_auth_method: "none", + }, + onSuccess(tokenset, client) { + const decoder = createDecoder(); + const claims = decoder(tokenset.access_token!) + + return config.onSuccess(claims, tokenset, client); + }, + }); + } +); diff --git a/packages/sst/src/node/auth/index.ts b/packages/sst/src/node/auth/index.ts index 68bc98e0c..f28a69f5c 100644 --- a/packages/sst/src/node/auth/index.ts +++ b/packages/sst/src/node/auth/index.ts @@ -9,6 +9,7 @@ export * from "./adapter/github.js"; export * from "./adapter/oidc.js"; export * from "./adapter/oauth.js"; export * from "./adapter/link.js"; +export * from "./adapter/openauth.js"; import { createProxy } from "../util/index.js"; diff --git a/www/docs/auth.md b/www/docs/auth.md index a72bb7c3c..39f21471d 100644 --- a/www/docs/auth.md +++ b/www/docs/auth.md @@ -479,6 +479,20 @@ FacebookAdapter({ --- +### OpenAuth + +Extends the `OauthAdapter` and pre-configures it to work with OpenAuth. + +```js +OpenauthAdapter({ + issuer: "https://auth.example.com", + clientID: "", + onSuccess: async (claims, tokenset) => {}, +}) +``` + +--- + ### Magic Links Issues magic links that you can send over email or SMS to verify users without the need of a password.