-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #58 from brandon-schabel/oauth
Oauth Implementation (Google preconfigured)
- Loading branch information
Showing
16 changed files
with
444 additions
and
31 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
Certainly! Let's create a README document to guide users through the process of creating a module in BNK (Bun Nook Kit). This document will be structured to be user-friendly, informative, and aligned with BNK's principles and coding style. | ||
|
||
--- | ||
|
||
# Creating a Module in BNK (Bun Nook Kit) | ||
|
||
## Overview | ||
This guide provides step-by-step instructions on how to create a new module for the BNK framework. Whether you're adding functionality like OAuth integration or something entirely different, these guidelines will help align the module with BNK's design philosophy and standards to ensure consistency. | ||
|
||
## Prerequisites | ||
- Familiarity with TypeScript and BNK's core concepts. | ||
- Understanding of the problem domain the module will address. | ||
|
||
## Step 1: Research and Requirements Gathering | ||
Before coding, understand the scope and requirements of the module. For instance, if you're building an OAuth module, research the OAuth 2.0 protocol, and identify the primary use cases you want to support. | ||
|
||
## Step 2: Designing the Module | ||
### 2.1 Define the API | ||
Design a clear and intuitive API for the module. Consider the functions and interfaces users will interact with. | ||
|
||
### 2.2 Plan the Architecture | ||
Ensure the module aligns with BNK's architecture. Use factory functions, avoid global state, and adhere to strong typing. | ||
|
||
### 2.3 Security and Performance | ||
Plan for security and performance from the start. This is especially important for modules handling sensitive data or requiring high efficiency. | ||
|
||
## Step 3: Implementation | ||
### 3.1 Setup | ||
Set up the basic structure of the module. Create a new directory and files as needed within the BNK project structure. | ||
|
||
### 3.2 Core Functionality | ||
Develop the core functionality of the module. Keep functions short and focused, and use descriptive names. | ||
|
||
### 3.3 Integration | ||
Ensure that the module integrates seamlessly with other BNK components. | ||
|
||
### 3.4 Error Handling | ||
Implement robust error handling to make the module resilient and reliable. | ||
|
||
## Step 4: Testing | ||
Write comprehensive tests for the module. Cover unit testing for individual functions and integration testing for the module as a whole. | ||
|
||
## Step 5: Documentation | ||
Document the module thoroughly. Include a usage guide, example implementations, and a detailed API reference. | ||
|
||
## Step 6: Community Feedback and Iteration | ||
Release a beta version of the module and encourage feedback from the BNK community. Iterate based on the feedback received. | ||
|
||
## Best Practices | ||
- **Follow BNK's Coding Style**: Adhere to the principles outlined in BNK's coding guidelines, such as using `const`, writing pure functions, and avoiding premature optimization. | ||
- **Use Descriptive Names**: Choose clear and descriptive names for functions, variables, and modules. | ||
- **Write Efficient Code**: Focus on practicality and optimization where necessary. Prioritize clarity and simplicity. | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
# rename this to .env anf ollow "Setup google oauth" instructions | ||
GOOGLE_OAUTH_CLIENT_ID="" | ||
GOOGLE_OAUTH_CLIENT_SECRET="" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
import { oAuthFactory } from "auth/oauth"; | ||
import { initGoogleOAuth } from "auth/oauth-providers"; | ||
import type { Routes } from "server"; | ||
import { serverFactory } from "server"; | ||
|
||
const googleClientId = Bun.env.GOOGLE_OAUTH_CLIENT_ID || ""; | ||
const googleClientSecret = Bun.env.GOOGLE_OAUTH_CLIENT_SECRET || ""; | ||
|
||
|
||
const googleOAuthConfig = initGoogleOAuth({ | ||
clientId: googleClientId, | ||
clientSecret: googleClientSecret, | ||
}); | ||
|
||
const googleOAuth = oAuthFactory(googleOAuthConfig); | ||
|
||
const routes = { | ||
"/login": { | ||
GET: () => { | ||
// you could pass a param for the provider | ||
const authUrl = googleOAuth.initiateOAuthFlow(); | ||
|
||
return new Response(null, { | ||
headers: { Location: authUrl }, | ||
status: 302, | ||
}); | ||
}, | ||
}, | ||
"/callback": { | ||
GET: async (req) => { | ||
try { | ||
const host = req.headers.get("host"); | ||
// Parse the URL and query parameters | ||
const url = new URL(req.url, `http://${host}`); | ||
const queryParams = new URLSearchParams(url.search); | ||
const code = queryParams.get("code"); | ||
|
||
if (!code) { | ||
return new Response("No code provided in query", { status: 400 }); | ||
} | ||
|
||
const tokenInfo = await googleOAuth.handleRedirect(code); | ||
|
||
console.log({ tokenInfo }); | ||
|
||
// Logic after successful authentication | ||
return new Response("Login Successful!"); | ||
} catch (error) { | ||
console.error(error); | ||
return new Response("Authentication failed", { status: 403 }); | ||
} | ||
}, | ||
}, | ||
"/": { | ||
GET: () => { | ||
// HTML content for the login page | ||
const htmlContent = `<html><body><h2>Login with Google</h2><button onclick="window.location.href='/login'">Login</button></body></html>`; | ||
return new Response(htmlContent, { | ||
headers: { "Content-Type": "text/html" }, | ||
}); | ||
}, | ||
}, | ||
} satisfies Routes; | ||
|
||
const server = serverFactory({ | ||
routes, | ||
}); | ||
|
||
server.start(3000); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
# OAuth Setup Instructions | ||
|
||
## Google OAuth Setup | ||
|
||
#### Step 1: Create a Google Cloud Project | ||
- **Access Google Cloud Console**: Go to [Google Cloud Console](https://console.cloud.google.com/). | ||
- **New Project**: Click 'New Project', name it, and create. | ||
|
||
#### Step 2: Configure OAuth Consent Screen | ||
- **Credentials Page**: Navigate to 'Credentials' under 'APIs & Services'. | ||
- **Consent Screen Setup**: Click 'Configure Consent Screen', select 'External', and create. | ||
- **Details**: Enter app name, support email, and developer email. Add optional details like logo and policy links. | ||
- **Save**: Click 'Save and Continue'. | ||
|
||
#### Step 3: Create OAuth 2.0 Credentials | ||
- **Credentials Creation**: Back on 'Credentials' page, select 'Create Credentials' > 'OAuth client ID'. | ||
- **Application Type**: Choose 'Web application'. | ||
- **Redirect URIs**: Add your redirect URI (/callback). | ||
- **Client ID & Secret**: After clicking 'Create', note down the client ID and secret. | ||
|
||
#### Step 4: Enable Required APIs | ||
- **API Library**: In 'Library', search and enable needed Google APIs. | ||
|
||
#### Step 5: Implement OAuth in Your App | ||
- **Integrate Credentials**: Use client ID and secret in your app's OAuth config. | ||
- **Handle Redirects**: Ensure handling of Google's redirects and token exchange. | ||
|
||
#### Step 6: Test and Deploy | ||
- **Testing**: Thoroughly test the OAuth flow. | ||
- **Verification and Deployment**: Submit for verification if needed and deploy. | ||
|
||
This guide provides a condensed overview of setting up Google OAuth. Adapt it based on your specific application needs and always prioritize security and privacy. | ||
|
||
## GitHub OAuth | ||
|
||
1. **Register Your Application**: Go to GitHub's Developer Settings and create a new OAuth application. | ||
2. **Client ID & Secret**: After registration, you'll receive a client ID and client secret. | ||
3. **Authorization URL**: Use `https://github.com/login/oauth/authorize` for user authorization. | ||
4. **Token URL**: Use `https://github.com/login/oauth/access_token` to exchange the code for a token. | ||
5. **Scopes**: Decide on the scopes you need, like `user:email` for email access. | ||
6. **Callback URL**: Set your callback URL that GitHub will redirect to after authentication. | ||
|
||
|
||
#### Don't Forget: | ||
|
||
1. **Submit for Verification**: If your application will be used by users outside your organization, you must submit your OAuth consent screen for verification by Google. | ||
|
||
|
||
## Meta (Facebook) OAuth | ||
|
||
1. **Facebook App**: Create a new app in the Facebook Developer portal. | ||
2. **Client ID & Secret**: Obtain these from your app's settings. | ||
3. **Authorization URL**: Use `https://www.facebook.com/v9.0/dialog/oauth`. | ||
4. **Token URL**: Use `https://graph.facebook.com/v9.0/oauth/access_token`. | ||
5. **Scopes**: Define scopes, such as `email` and `public_profile`. | ||
6. **Callback URL**: Set your redirect URI in the app settings. | ||
|
||
## Twitter OAuth | ||
|
||
1. **Create Twitter App**: Register your app on Twitter Developer Portal. | ||
2. **Keys and Tokens**: You'll get API key, API secret key, Access token, and Access token secret. | ||
3. **Authorization URL**: Use `https://api.twitter.com/oauth/authorize`. | ||
4. **Token URL**: Use `https://api.twitter.com/oauth/access_token`. | ||
5. **Callback URL**: Define your callback URL in the Twitter app settings. | ||
|
||
## Apple OAuth | ||
|
||
1. **Register with Apple Developer**: Create an app in Apple Developer portal. | ||
2. **Service ID & Secret**: Generate a Services ID and a secret key. | ||
3. **Authorization URL**: Use `https://appleid.apple.com/auth/authorize`. | ||
4. **Token URL**: Use `https://appleid.apple.com/auth/token`. | ||
5. **Scopes**: Define necessary scopes like `email` and `name`. | ||
6. **Redirect URIs**: Add your redirect URIs in the Apple Developer console. | ||
|
||
### Implementation Steps: | ||
|
||
1. **Setup OAuth Provider Configuration**: For each service, configure the details in your OAuth setup, similar to how you did with Google. | ||
2. **Redirect to Authorization URL**: On your login page, add buttons for each service that redirects to their respective authorization URL with the necessary query parameters. | ||
3. **Handle Callbacks**: Implement routes in your server to handle the callbacks, exchanging the authorization code for tokens. | ||
4. **User Authentication**: Use the tokens to fetch user details and authenticate or register them in your system. | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
import { OAuthConfig, OAuthProviderFn } from "./oauth-types"; | ||
|
||
export type ProvidersConfigRecord = Record< | ||
string, | ||
Omit<OAuthConfig, "clientId" | "clientSecret"> | ||
>; | ||
|
||
export const oAuthProviders = { | ||
google: { | ||
redirectUri: "http://localhost:3000/callback", // just a default placeholder | ||
authReqUrl: "https://accounts.google.com/o/oauth2/v2/auth", | ||
tokenUrl: "https://oauth2.googleapis.com/token", | ||
}, | ||
microsoft: { | ||
redirectUri: "http://localhost:3000/callback", | ||
authReqUrl: | ||
"https://login.microsoftonline.com/common/oauth2/v2.0/authorize", | ||
tokenUrl: "http://needtofind", | ||
}, | ||
} satisfies ProvidersConfigRecord; | ||
|
||
export const initGoogleOAuth: OAuthProviderFn = ( | ||
{ clientId, clientSecret }, | ||
options | ||
) => { | ||
const redirectUrl = options?.redirectUrl; | ||
return { | ||
...oAuthProviders.google, | ||
redirectUri: redirectUrl ? redirectUrl : oAuthProviders.google.redirectUri, | ||
clientId, | ||
clientSecret, | ||
}; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
export type OAuthHelpers = { | ||
getAuthorizationUrl(config: OAuthConfig): string; | ||
getToken(code: string, config: OAuthConfig): Promise<OAuthToken>; // Simplified for demonstration | ||
}; | ||
|
||
export type OAuthConfig = { | ||
clientId: string; | ||
clientSecret: string; | ||
// the server route that handles the redirect from the OAuth provider | ||
redirectUri: string; | ||
// the url that handles the token request from the OAuth provider | ||
tokenUrl: string; | ||
// the server route that handles the token request from the OAuth provider | ||
authReqUrl: string; | ||
}; | ||
|
||
export type OAuthToken = { | ||
accessToken: string; | ||
tokenType: string; | ||
expiresIn: number; // Time in seconds after which the token expires | ||
refreshToken?: string; // Optional, not all flows return a refresh token | ||
scope?: string; // Optional, scope of the access granted | ||
idToken?: string; // Optional, used in OpenID Connect (OIDC) | ||
// Additional fields can be added here depending on the OAuth provider | ||
}; | ||
|
||
export type OAuthProviderOptions = { | ||
redirectUrl: string; | ||
}; | ||
|
||
export type OAuthProviderCreds = Pick<OAuthConfig, "clientId" | "clientSecret">; | ||
export type OAuthProviderFn = ( | ||
config: OAuthProviderCreds, | ||
options?: OAuthProviderOptions | ||
) => OAuthConfig; | ||
export type OAuthProviderInitializer = (config: OAuthConfig) => OAuthHelpers; |
Oops, something went wrong.