Skip to content
This repository has been archived by the owner on Jun 13, 2022. It is now read-only.

Commit

Permalink
Merge pull request #173 from flexpa/feature/new-grantflow-exports
Browse files Browse the repository at this point in the history
feat: Added generic support to SmartAuthProvider
  • Loading branch information
kodiakhq[bot] authored Dec 16, 2021
2 parents 967e54f + 6d8bb0a commit c779076
Show file tree
Hide file tree
Showing 4 changed files with 17 additions and 23 deletions.
2 changes: 2 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ export {
SmartAuthRedirectQuerystring,
SmartAuthUrlQuerystring,
getAccessTokenFromClientCredentialFlow,
ClientCredentialsConfig,
AuthCodeConfig,
GrantFlow
} from "./smart-auth/index.js";

Expand Down
3 changes: 3 additions & 0 deletions src/smart-auth/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,9 @@ Sero will pass your scoped parameters in its generated authorization URL for you
* `SmartAuthUrlQuerystring` is a TS interface that types the Fastify route contraints for the auto-generated authorization URL starting point described above. You can customize scopes on a per request basis.
* `SmartAuthRedirectQuerystringSchema` is the AJV schema definition that corresponds to `SmartAuthRedirectQuerystring`, and can be used in the Fastify runtime - see example for use
* `getAccessTokenFromClientCredentialFlow` is a function to fetch a `client_credential` access token for a given `SmartAuthProvider`. It will also prioritize the passed in `scope: string[]` over the `smartAuthProvider.scope`, in case you need special scope(s) for this flow. This function is not decorated on the fastify server, so it can be called directly on a `SmartAuthProvider`.
* `ClientCredentialsConfig` a TS interface that types the auth configuration for the Client Credentials grant flow inside of a `SmartAuthProvider`
* `AuthCodeConfig` is a TS interface that types the auth configuration for the Authorization Code grant flow inside of a `SmartAuthProvider`
* `GrantFlow` is a TS union type for `"authorization_code"` and `"client_credentials"`

### Decorators

Expand Down
27 changes: 8 additions & 19 deletions src/smart-auth/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ export type SmartAuthScope = LaunchContext | Profile | Refresh | Resources

export type GrantFlow = "authorization_code" | "client_credentials"

export interface SmartAuthProvider {
export interface SmartAuthProvider<T = AuthCodeConfig | ClientCredentialsConfig> {
/** A name to label the provider */
name: string;
/** Client registration */
Expand All @@ -31,10 +31,10 @@ export interface SmartAuthProvider {
secret: string;
};
/** Auth related config */
auth: AuthCodeConfig | ClientCredentialsConfig;
auth: T;
}

interface SmartAuthConfig {
export interface SmartAuthConfig {
/** Supported grant flow */
grantFlow: GrantFlow;
/** String used to set the host to request the tokens to. Required. */
Expand All @@ -45,11 +45,11 @@ interface SmartAuthConfig {
tokenParams?: Record<string, any>;
}

interface ClientCredentialsConfig extends SmartAuthConfig {
export interface ClientCredentialsConfig extends SmartAuthConfig {
grantFlow: "client_credentials"
};

interface AuthCodeConfig extends SmartAuthConfig {
export interface AuthCodeConfig extends SmartAuthConfig {
grantFlow: "authorization_code"
scope: SmartAuthScope[];
/** An optional prefix to add to every route path */
Expand Down Expand Up @@ -115,10 +115,6 @@ export interface SmartAuthUrlQuerystring {
}
}

function supports(provider: SmartAuthProvider, flow: GrantFlow): boolean {
return provider.auth.grantFlow === flow
}

const defaultState = randomBytes(10).toString('hex')

function generateState(): string {
Expand All @@ -135,10 +131,9 @@ function routeCase(value: string): string {
return value.toLowerCase().replace(/\s/g,'-');
}

const oauthPlugin: FastifyPluginCallback<SmartAuthProvider> = function (http, options, next) {
const oauthPlugin: FastifyPluginCallback<SmartAuthProvider<AuthCodeConfig>> = function (http, options, next) {
const { name, client } = options;
supports(options, "authorization_code");
const auth = options.auth as AuthCodeConfig;
const auth = options.auth;
const { scope: defaultScope, redirect } = auth;

const prefix = auth?.pathPrefix || "/smart";
Expand Down Expand Up @@ -215,8 +210,6 @@ const oauthPlugin: FastifyPluginCallback<SmartAuthProvider> = function (http, op
getNewAccessTokenUsingRefreshToken,
generateAuthorizationUri
})


} catch (e) {
next(e as Error)
return
Expand All @@ -226,13 +219,9 @@ const oauthPlugin: FastifyPluginCallback<SmartAuthProvider> = function (http, op
}

export const getAccessTokenFromClientCredentialFlow = async (
smartAuthProvider: SmartAuthProvider,
smartAuthProvider: SmartAuthProvider<ClientCredentialsConfig>,
scope?: string[]
): Promise<AccessToken | undefined> => {
if (!supports(smartAuthProvider, "client_credentials")) {
throw new Error(`SmartAuthProvider ${smartAuthProvider.name} does not support client_credentials - client_credentials must be explicitly set as a suppoedGrantFlow`)
}

const clientCredentialsOptions = {
client: smartAuthProvider.client,
auth: {
Expand Down
8 changes: 4 additions & 4 deletions test/smart-auth/idp.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { SmartAuthProvider } from "../../src";
import { AuthCodeConfig, ClientCredentialsConfig, SmartAuthProvider } from "../../src";

export const AuthorizationCodeExample: SmartAuthProvider = {
export const AuthorizationCodeExample: SmartAuthProvider<AuthCodeConfig> = {
name: "idp",
client: {
id: "123",
Expand All @@ -17,7 +17,7 @@ export const AuthorizationCodeExample: SmartAuthProvider = {
},
};

export const badNameExample: SmartAuthProvider = {
export const badNameExample: SmartAuthProvider<AuthCodeConfig> = {
name: "Bad Name",
client: {
id: "123",
Expand All @@ -34,7 +34,7 @@ export const badNameExample: SmartAuthProvider = {
}
};

export const ClientCredentialsExample: SmartAuthProvider = {
export const ClientCredentialsExample: SmartAuthProvider<ClientCredentialsConfig> = {
name: 'smart-stub',
client: {
id: 'foo',
Expand Down

0 comments on commit c779076

Please sign in to comment.