Authentication & Users

Social Login

Configure authentication via Google, GitHub, Facebook and other OAuth providers.

Nuda Kit uses AdonisJS Ally to handle social authentication. It comes pre-configured with support for Google, GitHub, and Facebook, but you can easily add Twitter, Discord, LinkedIn, and many others.

How It Works

The OAuth flow in a decoupled (Nuxt + AdonisJS) environment works like this:

User Initiates Login

The user clicks a social login button (e.g., "Login with Google") on the frontend.

Redirect to Provider

The browser navigates to your API endpoint (e.g., /users/login/google), which redirects to the provider's OAuth page.

User Authorizes

The user accepts permissions on the provider's page (Google, GitHub, or Facebook).

Callback Processing

The provider redirects back to your API callback endpoint (e.g., /users/login/google/callback). AdonisJS verifies the token and retrieves the user's profile.

User Creation or Lookup

The system either finds an existing user by email or creates a new account with the profile data from the provider.

Token Generation & Redirect

A JWT access token is generated, and the user is redirected back to your Nuxt frontend with the token as a query parameter (e.g., /auth/login?token={JWT_TOKEN}).

API Routes

The following routes are registered for social authentication:

ProviderRedirect URLCallback URL
GoogleGET /users/login/googleGET /users/login/google/callback
GitHubGET /users/login/githubGET /users/login/github/callback
FacebookGET /users/login/facebookGET /users/login/facebook/callback

Configuration

To enable a social provider, you need to obtain the Client ID and Client Secret from the provider's developer console.

1. Get Credentials

When setting up the OAuth app, make sure to add the callback URL as an authorized redirect URI. For example: https://api.yourdomain.com/users/login/google/callback

2. Update Environment Variables

Add the credentials to your backend/.env file:

# Google
GOOGLE_CLIENT_ID=your_google_client_id
GOOGLE_CLIENT_SECRET=your_google_client_secret
GOOGLE_CALLBACK_URL=http://localhost:3333/users/login/google/callback

# GitHub
GITHUB_CLIENT_ID=your_github_client_id
GITHUB_CLIENT_SECRET=your_github_client_secret
GITHUB_CALLBACK_URL=http://localhost:3333/users/login/github/callback

# Facebook
FACEBOOK_CLIENT_ID=your_facebook_client_id
FACEBOOK_CLIENT_SECRET=your_facebook_client_secret
FACEBOOK_CALLBACK_URL=http://localhost:3333/users/login/facebook/callback
All social login environment variables are optional. You only need to configure the providers you want to use.

Ally Configuration

The social providers are configured in backend/config/ally.ts:

import env from '#start/env'
import { defineConfig, services } from '@adonisjs/ally'

const allyConfig = defineConfig({
  facebook: services.facebook({
    clientId: env.get('FACEBOOK_CLIENT_ID') || '',
    clientSecret: env.get('FACEBOOK_CLIENT_SECRET') || '',
    callbackUrl: env.get('FACEBOOK_CALLBACK_URL') || '',
  }),
  github: services.github({
    clientId: env.get('GITHUB_CLIENT_ID') || '',
    clientSecret: env.get('GITHUB_CLIENT_SECRET') || '',
    callbackUrl: env.get('GITHUB_CALLBACK_URL') || '',
  }),
  google: services.google({
    clientId: env.get('GOOGLE_CLIENT_ID') || '',
    clientSecret: env.get('GOOGLE_CLIENT_SECRET') || '',
    callbackUrl: env.get('GOOGLE_CALLBACK_URL') || '',
  }),
})

export default allyConfig

Frontend Integration

On the frontend, social login is triggered by navigating to the API endpoint. Here's how it's implemented in LoginWithEmailPasswordForm.vue:

<script setup lang="ts">
const config = useRuntimeConfig()

const onLoginWithGoogle = () => {
  navigateTo(`${config.public.apiBaseUrl}/users/login/google`, { external: true })
}

const onLoginWithGithub = () => {
  navigateTo(`${config.public.apiBaseUrl}/users/login/github`, { external: true })
}

const onLoginWithFacebook = () => {
  navigateTo(`${config.public.apiBaseUrl}/users/login/facebook`, { external: true })
}
</script>

The login page (frontend/app/pages/app/auth/login.vue) automatically handles the token returned from the OAuth flow:

<script setup lang="ts">
const { setToken } = useAuthCookie()
const queryClient = useQueryClient()

onMounted(() => {
  const token = useRoute().query.token
  if (token) {
    setToken(token as string)
    queryClient.invalidateQueries({ queryKey: ['teams'] })
    toast.success('Logged in successfully')
    navigateTo('/app')
  }
})
</script>

Error Handling

The OAuth callback handles several error scenarios:

ErrorDescription
access_deniedUser denied the permission request
state_mismatchOAuth state mismatch (possible CSRF attack)
errorGeneric error from the provider
user_marked_for_deletionUser account is scheduled for deletion

Errors are passed back to the frontend as query parameters: /auth/login?error=true&error_message=access_denied

Adding More Providers

AdonisJS Ally supports many OAuth providers out of the box. To add a new provider:

  1. Update the Ally config in backend/config/ally.ts:
const allyConfig = defineConfig({
  // ... existing providers
  twitter: services.twitter({
    clientId: env.get('TWITTER_CLIENT_ID') || '',
    clientSecret: env.get('TWITTER_CLIENT_SECRET') || '',
    callbackUrl: env.get('TWITTER_CALLBACK_URL') || '',
  }),
})
  1. Add environment variables to backend/start/env.ts:
TWITTER_CLIENT_ID: Env.schema.string.optional(),
TWITTER_CLIENT_SECRET: Env.schema.string.optional(),
TWITTER_CALLBACK_URL: Env.schema.string.optional(),
  1. Create a controller following the pattern in backend/app/controllers/users/login_user_google_controller.ts.
  2. Register routes in backend/start/routes/users.ts:
router.get('/login/twitter', [LoginUserTwitterController, 'redirect'])
router.get('/login/twitter/callback', [LoginUserTwitterController, 'callback'])
  1. Add the button to the frontend login/signup forms.
For a complete list of supported providers and their configuration options, see the AdonisJS Ally documentation.