Skip to content
Init is here / May 19 - 23
Back

Can't Login via Discord OAuth

  • 0
  • Self Hosted
  • Auth
  • Web
Jonny
12 Feb, 2025, 22:09

Hey :peepoShy: I receive "AppwriteException: User (role: guests) missing scope (account)" & "<appwriteUrl>/v1/account 401 (Unauthorized)" after Discord redirect. The Email & Password login works as intended.

TL;DR
Developers are having trouble logging in via Discord OAuth, receiving errors related to missing scopes. The issue may be due to third-party cookies not being enabled. To resolve this, developers can try inspecting browser network logs and ensure that third-party cookies are enabled. Additionally, custom domains may need to be configured for production. The provided code includes the setup for Appwrite and authentication services, including functions for checking login status, starting OAuth2 session with Discord, and logging out users.
Jonny
12 Feb, 2025, 22:14

appwrite.service.ts

TypeScript
@Injectable({
  providedIn: 'root'
})
export class AppwriteService {
  private readonly client: Client;
  public account: Account;
  public databases: Databases;
  public avatars: Avatars;

  constructor() {
    this.client = new Client()
      .setEndpoint(environment.appwriteUrl)
      .setProject(environment.projectId)
      .setLocale('de-DE');

    this.account = new Account(this.client);
    this.databases = new Databases(this.client);
    this.avatars = new Avatars(this.client);
  }
}

auth.service.ts

TypeScript
@Injectable({
  providedIn: 'root',
})
export class AuthService {
  private databaseId = environment.databases['users'].databaseId;
  private collectionId = environment.databases['users'].collections['userData'].collectionId;

  public user = signal<Models.User<any> | null>(null); // Signal for the current User
  public isLoggedIn = signal<boolean>(false); // Signal for login status

  constructor(
    private toast: ToastService,
    private router: Router,
    private appwrite: AppwriteService,
    private logger: NGXLogger
  ) {
    // Currently disabled for testing
    // Normaly restores the Session but as this is not working I'm calling this from callback
    // will be re enabled when session is working again with oAuth
    // checkLogin()
  }

  /** Check for Session and Login */
  public async checkLogin(): Promise<void> {
    try {
      this.logger.info('Trying to get User');
      const userData = await this.appwrite.account.get();
      this.logger.info('Trying to get Session');
      const session = await this.appwrite.account.getSession('current');

      // User is logged in
      this.user.set(userData);
      this.isLoggedIn.set(true);
      this.logger.info('User found successfully');
    } catch (error) {
      this.logger.error('No User found:');
      this.logger.error(error);
      this.user.set(null);
      this.isLoggedIn.set(false);
    }
  }

  /** Start OAuth2-Session with Discord */
  async loginWithDiscord(): Promise<void> {
    // Remove current session
    try {
      await this.appwrite.account.deleteSession('current');
    } catch (err) {
      console.error('Session deletion failed');
    }


    this.logger.info('Logging in with Discord');
    await this.appwrite.account.createOAuth2Session(
      OAuthProvider.Discord,
      environment.baseUrl + '/callback',
      environment.baseUrl + '/error',
      ['identify', 'email']
    )
  }

  /** Sign Out the User */
  async logout(): Promise<void> {
    this.logger.info('Logging out');
    try {
      await this.appwrite.account.deleteSession('current');
      this.user.set(null);
      this.isLoggedIn.set(false);
      this.logger.info('Logged out successfully');
    } catch (error) {
      this.logger.error('Logout failed:', error);
      this.user.set(null);
      this.isLoggedIn.set(false);
    }
  }
}

callback.component.ts

TypeScript
@Component({
  selector: 'app-callback',
  imports: [],
  templateUrl: './callback.component.html',
  styleUrl: './callback.component.scss'
})
export class CallbackComponent {
  constructor(
    private authService: AuthService,
    private appwrite: AppwriteService,
    private router: Router,
    private logger: NGXLogger
  ) {
    this.logger.warn(this.router.url);
    this.logger.warn(window.location.href);

    this.handleCallback();
  }

  private async handleCallback() {
    this.logger.info('Got callback from OAuth provider');
    this.authService.checkLogin();
  }
}
Jonny
12 Feb, 2025, 22:16

Error from /account

TypeScript
{
    "message": "User (role: guests) missing scope (account)",
    "code": 401,
    "type": "general_unauthorized_scope",
    "version": "1.6.0"
}
Steven
12 Feb, 2025, 22:17

You have SSR?

Jonny
12 Feb, 2025, 22:17

No

Steven
12 Feb, 2025, 22:18

It's probably a 3rd party cookie problem.

For local development, maybe you can change your browser settings to enable 3rd party cookies.

In production, you'll need to use custom domains

Jonny
12 Feb, 2025, 22:18

I get something stored in the cookies but its a_session_projectId_legacy

Jonny
12 Feb, 2025, 22:20

And 3rd Party Cookies are enabled

Steven
12 Feb, 2025, 22:25

There should be a a_session_projectId one too

Steven
12 Feb, 2025, 22:26

you can try inspecting the browser network logs to see if the cookie is there or if there any errors

Jonny
12 Feb, 2025, 22:26

I only get the legacy cookie

Steven
12 Feb, 2025, 22:27

inspect the browser network logs

Reply

Reply to this thread by joining our Discord

Reply on Discord

Need support?

Join our Discord

Get community support by joining our Discord server.

Join Discord

Get premium support

Join Appwrite Pro and get email support from our team.

Learn more