Replace all marketing placeholder content with real MYeasyCMS content
- Logo: Replace generic Makerkit SVG with MYeasyCMS branded logo (grid icon + styled text) - Blog: Replace 3 SaaS placeholder posts with 5 real articles (Vereinsverwaltung, SEPA, Website, DSGVO, Mitglieder-Tipps) - Changelog: Replace 6 generic entries with real feature announcements (Verbandsverwaltung, Fischerei, Dateien, Kurse, Einladungen, i18n) - Documentation: Rewrite all 20 docs from Makerkit references to MYeasyCMS content - FAQ: Replace 6 generic SaaS questions with 10 real MYeasyCMS questions - Navigation: Replace Changelog link with Contact in main nav - Footer: Reorganize into Product/Company/Legal sections - Translations: Update all EN marketing strings to match real Com.BISS content
This commit is contained in:
@@ -1,395 +1,31 @@
|
||||
---
|
||||
title: "OAuth"
|
||||
description: "Sign in with Google, GitHub, and other OAuth providers."
|
||||
title: "Mitgliederportal"
|
||||
description: "Das Mitgliederportal ermöglicht Vereinsmitgliedern den Zugriff auf ihre eigenen Daten."
|
||||
publishedAt: 2024-04-11
|
||||
order: 3
|
||||
status: "published"
|
||||
---
|
||||
|
||||
> **Note:** This is mock/placeholder content for demonstration purposes.
|
||||
Das Mitgliederportal ist der Bereich von MYeasyCMS, der für die Vereinsmitglieder selbst zugänglich ist.
|
||||
|
||||
Allow users to sign in with their existing accounts from Google, GitHub, and other providers.
|
||||
## Funktionen für Mitglieder
|
||||
|
||||
## Supported Providers
|
||||
Über das Portal können Mitglieder:
|
||||
|
||||
Supabase supports many OAuth providers:
|
||||
- Google
|
||||
- GitHub
|
||||
- GitLab
|
||||
- Bitbucket
|
||||
- Azure
|
||||
- Facebook
|
||||
- Twitter
|
||||
- Discord
|
||||
- Slack
|
||||
- And more...
|
||||
- **Stammdaten einsehen und aktualisieren** — Adresse, Telefonnummer, E-Mail
|
||||
- **Kursanmeldungen** — Sich für Kurse und Veranstaltungen anmelden
|
||||
- **Beitragshistorie** — Ihre Zahlungshistorie einsehen
|
||||
- **Dokumente** — Persönliche Dokumente herunterladen (Ausweis, Bestätigungen)
|
||||
- **Newsletter** — Newsletter-Abonnement verwalten
|
||||
|
||||
## Setting Up OAuth
|
||||
## Zugang einrichten
|
||||
|
||||
### Configure in Supabase Dashboard
|
||||
Mitglieder erhalten Zugang zum Portal über die Vereinswebsite. Der Login erfolgt mit E-Mail-Adresse und Passwort.
|
||||
|
||||
1. Go to **Authentication** → **Providers**
|
||||
2. Enable your desired provider (e.g., Google)
|
||||
3. Add your OAuth credentials:
|
||||
- **Client ID**
|
||||
- **Client Secret**
|
||||
- **Redirect URL**: `https://your-project.supabase.co/auth/v1/callback`
|
||||
## Datenschutz
|
||||
|
||||
### Google OAuth Setup
|
||||
Jedes Mitglied sieht ausschließlich seine eigenen Daten. Ein Zugriff auf andere Mitgliederdaten oder Verwaltungsfunktionen ist nicht möglich.
|
||||
|
||||
1. Go to [Google Cloud Console](https://console.cloud.google.com)
|
||||
2. Create a new project or select existing
|
||||
3. Enable Google+ API
|
||||
4. Create OAuth 2.0 credentials
|
||||
5. Add authorized redirect URIs:
|
||||
- Production: `https://your-project.supabase.co/auth/v1/callback`
|
||||
- Development: `http://localhost:54321/auth/v1/callback`
|
||||
## Kontoverknüpfung
|
||||
|
||||
### GitHub OAuth Setup
|
||||
|
||||
1. Go to GitHub Settings → Developer Settings → OAuth Apps
|
||||
2. Click "New OAuth App"
|
||||
3. Fill in details:
|
||||
- **Application name**: Your App
|
||||
- **Homepage URL**: `https://yourapp.com`
|
||||
- **Authorization callback URL**: `https://your-project.supabase.co/auth/v1/callback`
|
||||
4. Copy Client ID and Client Secret to Supabase
|
||||
|
||||
## Implementation
|
||||
|
||||
### OAuth Sign In Button
|
||||
|
||||
```tsx
|
||||
'use client';
|
||||
|
||||
import { signInWithOAuthAction } from '../_lib/actions';
|
||||
|
||||
export function OAuthButtons() {
|
||||
const handleGoogleSignIn = async () => {
|
||||
await signInWithOAuthAction('google');
|
||||
};
|
||||
|
||||
const handleGitHubSignIn = async () => {
|
||||
await signInWithOAuthAction('github');
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="space-y-2">
|
||||
<button
|
||||
onClick={handleGoogleSignIn}
|
||||
className="w-full flex items-center justify-center gap-2 border rounded-lg p-2"
|
||||
>
|
||||
<GoogleIcon />
|
||||
Continue with Google
|
||||
</button>
|
||||
|
||||
<button
|
||||
onClick={handleGitHubSignIn}
|
||||
className="w-full flex items-center justify-center gap-2 border rounded-lg p-2"
|
||||
>
|
||||
<GitHubIcon />
|
||||
Continue with GitHub
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
### Server Action
|
||||
|
||||
```typescript
|
||||
'use server';
|
||||
|
||||
import { enhanceAction } from '@kit/next/actions';
|
||||
import { getSupabaseServerClient } from '@kit/supabase/server-client';
|
||||
import * as z from 'zod';
|
||||
|
||||
const OAuthProviderSchema = z.enum([
|
||||
'google',
|
||||
'github',
|
||||
'gitlab',
|
||||
'azure',
|
||||
'facebook',
|
||||
]);
|
||||
|
||||
export const signInWithOAuthAction = enhanceAction(
|
||||
async (provider) => {
|
||||
const client = getSupabaseServerClient();
|
||||
const origin = process.env.NEXT_PUBLIC_SITE_URL!;
|
||||
|
||||
const { data, error } = await client.auth.signInWithOAuth({
|
||||
provider,
|
||||
options: {
|
||||
redirectTo: `${origin}/auth/callback`,
|
||||
},
|
||||
});
|
||||
|
||||
if (error) throw error;
|
||||
|
||||
// Redirect to OAuth provider
|
||||
redirect(data.url);
|
||||
},
|
||||
{
|
||||
schema: OAuthProviderSchema,
|
||||
}
|
||||
);
|
||||
```
|
||||
|
||||
### OAuth Callback Handler
|
||||
|
||||
```typescript
|
||||
// app/auth/callback/route.ts
|
||||
import { createRouteHandlerClient } from '@supabase/auth-helpers-nextjs';
|
||||
import { cookies } from 'next/headers';
|
||||
import { NextResponse } from 'next/server';
|
||||
|
||||
export async function GET(request: Request) {
|
||||
const requestUrl = new URL(request.url);
|
||||
const code = requestUrl.searchParams.get('code');
|
||||
|
||||
if (code) {
|
||||
const cookieStore = cookies();
|
||||
const supabase = createRouteHandlerClient({ cookies: () => cookieStore });
|
||||
|
||||
await supabase.auth.exchangeCodeForSession(code);
|
||||
}
|
||||
|
||||
// Redirect to home page
|
||||
return NextResponse.redirect(new URL('/home', request.url));
|
||||
}
|
||||
```
|
||||
|
||||
## Customizing OAuth Flow
|
||||
|
||||
### Scopes
|
||||
|
||||
Request specific permissions:
|
||||
|
||||
```typescript
|
||||
await client.auth.signInWithOAuth({
|
||||
provider: 'google',
|
||||
options: {
|
||||
scopes: 'email profile https://www.googleapis.com/auth/calendar',
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
### Query Parameters
|
||||
|
||||
Pass custom parameters:
|
||||
|
||||
```typescript
|
||||
await client.auth.signInWithOAuth({
|
||||
provider: 'azure',
|
||||
options: {
|
||||
queryParams: {
|
||||
prompt: 'consent',
|
||||
access_type: 'offline',
|
||||
},
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
### Skip Browser Redirect
|
||||
|
||||
For mobile apps or custom flows:
|
||||
|
||||
```typescript
|
||||
const { data } = await client.auth.signInWithOAuth({
|
||||
provider: 'google',
|
||||
options: {
|
||||
skipBrowserRedirect: true,
|
||||
},
|
||||
});
|
||||
|
||||
// data.url contains the OAuth URL
|
||||
// Handle redirect manually
|
||||
```
|
||||
|
||||
## Account Linking
|
||||
|
||||
### Linking Additional Providers
|
||||
|
||||
Allow users to link multiple OAuth accounts:
|
||||
|
||||
```typescript
|
||||
export const linkOAuthProviderAction = enhanceAction(
|
||||
async (provider) => {
|
||||
const client = getSupabaseServerClient();
|
||||
const user = await requireAuth();
|
||||
|
||||
const { data, error } = await client.auth.linkIdentity({
|
||||
provider,
|
||||
});
|
||||
|
||||
if (error) throw error;
|
||||
|
||||
redirect(data.url);
|
||||
},
|
||||
{ schema: OAuthProviderSchema, auth: true }
|
||||
);
|
||||
```
|
||||
|
||||
### Unlinking Providers
|
||||
|
||||
```typescript
|
||||
export const unlinkOAuthProviderAction = enhanceAction(
|
||||
async ({ provider, identityId }) => {
|
||||
const client = getSupabaseServerClient();
|
||||
|
||||
const { error } = await client.auth.unlinkIdentity({
|
||||
identity_id: identityId,
|
||||
});
|
||||
|
||||
if (error) throw error;
|
||||
|
||||
revalidatePath('/settings/security');
|
||||
},
|
||||
{
|
||||
schema: z.object({
|
||||
provider: z.string(),
|
||||
identityId: z.string(),
|
||||
}),
|
||||
auth: true,
|
||||
}
|
||||
);
|
||||
```
|
||||
|
||||
### Viewing Linked Identities
|
||||
|
||||
```typescript
|
||||
import { getSupabaseServerClient } from '@kit/supabase/server-client';
|
||||
|
||||
export async function getLinkedIdentities() {
|
||||
const client = getSupabaseServerClient();
|
||||
const { data: { user } } = await client.auth.getUser();
|
||||
|
||||
return user?.identities || [];
|
||||
}
|
||||
```
|
||||
|
||||
## User Data from OAuth
|
||||
|
||||
### Accessing Provider Data
|
||||
|
||||
```typescript
|
||||
const { data: { user } } = await client.auth.getUser();
|
||||
|
||||
// User metadata from provider
|
||||
const {
|
||||
full_name,
|
||||
avatar_url,
|
||||
email,
|
||||
} = user.user_metadata;
|
||||
|
||||
// Provider-specific data
|
||||
const identities = user.identities || [];
|
||||
const googleIdentity = identities.find(i => i.provider === 'google');
|
||||
|
||||
console.log(googleIdentity?.identity_data);
|
||||
```
|
||||
|
||||
### Storing Additional Data
|
||||
|
||||
```typescript
|
||||
export const completeOAuthProfileAction = enhanceAction(
|
||||
async (data) => {
|
||||
const client = getSupabaseServerClient();
|
||||
const user = await requireAuth();
|
||||
|
||||
// Update user metadata
|
||||
await client.auth.updateUser({
|
||||
data: {
|
||||
username: data.username,
|
||||
bio: data.bio,
|
||||
},
|
||||
});
|
||||
|
||||
// Update profile in database
|
||||
await client.from('profiles').upsert({
|
||||
id: user.id,
|
||||
username: data.username,
|
||||
bio: data.bio,
|
||||
avatar_url: user.user_metadata.avatar_url,
|
||||
});
|
||||
|
||||
redirect('/home');
|
||||
},
|
||||
{ schema: ProfileSchema, auth: true }
|
||||
);
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
### Enable OAuth in Config
|
||||
|
||||
```typescript
|
||||
// config/auth.config.ts
|
||||
export const authConfig = {
|
||||
providers: {
|
||||
emailPassword: true,
|
||||
oAuth: ['google', 'github'],
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
### Conditional Rendering
|
||||
|
||||
```tsx
|
||||
import { authConfig } from '~/config/auth.config';
|
||||
|
||||
export function AuthProviders() {
|
||||
return (
|
||||
<>
|
||||
{authConfig.providers.emailPassword && <EmailPasswordForm />}
|
||||
|
||||
{authConfig.providers.oAuth?.includes('google') && (
|
||||
<GoogleSignInButton />
|
||||
)}
|
||||
|
||||
{authConfig.providers.oAuth?.includes('github') && (
|
||||
<GitHubSignInButton />
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Redirect URI Mismatch
|
||||
|
||||
Ensure redirect URIs match exactly:
|
||||
- Check Supabase Dashboard → Authentication → URL Configuration
|
||||
- Verify OAuth app settings in provider console
|
||||
- Use exact URLs (including http/https)
|
||||
|
||||
### Missing Email
|
||||
|
||||
Some providers don't share email by default:
|
||||
|
||||
```typescript
|
||||
const { data: { user } } = await client.auth.getUser();
|
||||
|
||||
if (!user.email) {
|
||||
// Request email separately or prompt user
|
||||
redirect('/auth/complete-profile');
|
||||
}
|
||||
```
|
||||
|
||||
### Rate Limiting
|
||||
|
||||
OAuth providers may rate limit requests:
|
||||
- Cache OAuth tokens appropriately
|
||||
- Don't make excessive authorization requests
|
||||
- Handle rate limit errors gracefully
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. **Request minimum scopes** - Only ask for what you need
|
||||
2. **Handle errors gracefully** - OAuth can fail for many reasons
|
||||
3. **Verify email addresses** - Some providers don't verify emails
|
||||
4. **Support account linking** - Let users connect multiple providers
|
||||
5. **Provide fallback** - Always offer email/password as backup
|
||||
6. **Log OAuth events** - Track sign-ins and linking attempts
|
||||
7. **Test thoroughly** - Test with real provider accounts
|
||||
Mitglieder, die in mehreren Vereinen aktiv sind, können ihre Konten verknüpfen und zwischen den Vereinen wechseln, ohne sich erneut anmelden zu müssen.
|
||||
|
||||
Reference in New Issue
Block a user