A Powerful Flutter Plugin Allowing Developers to Auth/Share

tencent_kit

flutter版腾讯(QQ)SDK

相关工具

dart/flutter 私服

docs

android

android {
    defaultConfig{
        addManifestPlaceholders([
                TENCENT_APP_ID: "your tencent appId"
        ])
    }
}
# 混淆已打入 Library,随 Library 引用,自动添加到 apk 打包混淆

ios

出于插件的基本需求,将 SDK 的 module.modulemap 内容修改

改前
module TencentOpenApi{
    umbrella header "TencentOpenApiUmbrellaHeader.h"
    export *
}

改后
framework module TencentOpenApi{
    umbrella header "TencentOpenApiUmbrellaHeader.h"
    export *
}
在Xcode中,选择你的工程设置项,选中“TARGETS”一栏,在“info”标签栏的“URL type“添加“URL scheme”为你所注册的应用程序id

URL Types
tencent: identifier=tencent schemes=tencent${appId}
iOS 9系统策略更新,限制了http协议的访问,此外应用需要在“Info.plist”中将要使用的URL Schemes列为白名单,才可正常检查其他应用是否安装。

	<key>LSApplicationQueriesSchemes</key>
	<array>
		<string>tim</string>
		<string>mqq</string>
		<string>mqqapi</string>
		<string>mqqbrowser</string>
		<string>mttbrowser</string>
		<string>mqqOpensdkSSoLogin</string>
		<string>mqqopensdkapiV2</string>
		<string>mqqopensdkapiV4</string>
		<string>mqzone</string>
		<string>mqzoneopensdk</string>
		<string>mqzoneopensdkapi</string>
		<string>mqzoneopensdkapi19</string>
		<string>mqzoneopensdkapiV2</string>
		<string>mqqapiwallet</string>
		<string>mqqopensdkfriend</string>
		<string>mqqopensdkavatar</string>
		<string>mqqopensdkminiapp</string>
		<string>mqqopensdkdataline</string>
		<string>mqqgamebindinggroup</string>
		<string>mqqopensdkgrouptribeshare</string>
		<string>tencentapi.qq.reqContent</string>
		<string>tencentapi.qzone.reqContent</string>
		<string>mqqthirdappgroup</string>
		<string>mqqopensdklaunchminiapp</string>
		<string>mqqopensdkproxylogin</string>
		<string>mqqopensdknopasteboard</string>
		<string>mqqopensdkcheckauth</string>
	</array>
Universal Links

Capabilities -> Associated Domain -> Domain -> applinks:${your applinks}

flutter

分享类型说说(图/文/视频)文本图片音乐视频网页
QQ不支持不支持支持支持不支持支持
QZone支持不支持不支持不支持不支持支持

break change

  • 4.0.0: 按标准插件书写重构
  • 3.1.0: 新增 setIsPermissionGranted 函数,设置是否已授权获取设备信息/是否同意隐私协议
  • 3.0.0: 重构
  • 2.1.0: nullsafety & 不再支持 Android embedding v1 & Tencent 单例

compat

snapshot

dependencies:
  tencent_kit:
    git:
      url: https://github.com/rxreader/tencent_kit.git
  • release
dependencies:
  tencent_kit: ^${latestTag}
  • example

示例

Star History

stars

Use this package as a library

Depend on it

Run this command:

With Flutter:

 $ flutter pub add tencent_kit

This will add a line like this to your package's pubspec.yaml (and run an implicit flutter pub get):

dependencies:
  tencent_kit: ^4.0.0

Alternatively, your editor might support flutter pub get. Check the docs for your editor to learn more.

Import it

Now in your Dart code, you can use:

import 'package:tencent_kit/tencent_kit.dart'; 

example/lib/main.dart

import 'dart:async';
import 'dart:io';

import 'package:flutter/material.dart';
import 'package:flutter_cache_manager/flutter_cache_manager.dart';
import 'package:tencent_kit/tencent_kit.dart';
import 'package:tencent_kit_example/api/model/tencent_api_resp.dart';
import 'package:tencent_kit_example/api/model/tencent_unionid_resp.dart';
import 'package:tencent_kit_example/api/tencent_api.dart';

const String _TENCENT_APPID = 'your tencent appId';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({
    super.key,
  });

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Home(),
    );
  }
}

class Home extends StatefulWidget {
  const Home({
    super.key,
  });

  @override
  State<StatefulWidget> createState() {
    return _HomeState();
  }
}

class _HomeState extends State<Home> {
  late final StreamSubscription<BaseResp> _respSubs;

  LoginResp? _loginResp;

  @override
  void initState() {
    super.initState();
    _respSubs = Tencent.instance.respStream().listen(_listenLogin);
  }

  void _listenLogin(BaseResp resp) {
    if (resp is LoginResp) {
      _loginResp = resp;
      final String content = 'login: ${resp.openid} - ${resp.accessToken}';
      _showTips('登录', content);
    } else if (resp is ShareMsgResp) {
      final String content = 'share: ${resp.ret} - ${resp.msg}';
      _showTips('分享', content);
    }
  }

  @override
  void dispose() {
    _respSubs.cancel();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Tencent Kit Demo'),
      ),
      body: ListView(
        children: <Widget>[
          ListTile(
            title: Text('3.1.0 之后的版本请先获取权限'),
            onTap: () async {
              await Tencent.instance.setIsPermissionGranted(granted: true);
              _showTips('授权', '已授权获取设备信息/同意隐私协议');
            },
          ),
          ListTile(
            title: Text('注册APP'),
            onTap: () async {
              await Tencent.instance.registerApp(appId: _TENCENT_APPID);
              _showTips('注册APP', '注册成功');
            },
          ),
          ListTile(
            title: Text('环境检查'),
            onTap: () async {
              final String content =
                  'QQ install: ${await Tencent.instance.isQQInstalled()}\nTIM install: ${await Tencent.instance.isTIMInstalled()}';
              _showTips('环境检查', content);
            },
          ),
          ListTile(
            title: Text('登录'),
            onTap: () {
              Tencent.instance.login(
                scope: <String>[TencentScope.GET_SIMPLE_USERINFO],
              );
            },
          ),
          ListTile(
            title: Text('获取用户信息'),
            onTap: () async {
              if ((_loginResp?.isSuccessful ?? false) &&
                  !(_loginResp!.isExpired ?? true)) {
                final TencentUserInfoResp userInfo =
                    await TencentApi.getUserInfo(
                  appId: _TENCENT_APPID,
                  openid: _loginResp!.openid!,
                  accessToken: _loginResp!.accessToken!,
                );
                if (userInfo.isSuccessful) {
                  _showTips('用户信息',
                      '${userInfo.nickname} - ${userInfo.gender} - ${userInfo.genderType}');
                } else {
                  _showTips('用户信息', '${userInfo.ret} - ${userInfo.msg}');
                }
              }
            },
          ),
          ListTile(
            title: Text('获取UnionID'),
            onTap: () async {
              if ((_loginResp?.isSuccessful ?? false) &&
                  !(_loginResp!.isExpired ?? true)) {
                final TencentUnionidResp unionid = await TencentApi.getUnionId(
                  accessToken: _loginResp!.accessToken!,
                );
                if (unionid.isSuccessful) {
                  _showTips('UnionID',
                      '${unionid.clientId} - ${unionid.openid} - ${unionid.unionid}');
                } else {
                  _showTips('UnionID',
                      '${unionid.error} - ${unionid.errorDescription}');
                }
              }
            },
          ),
          ListTile(
            title: Text('分享说说'),
            onTap: () {
              Tencent.instance.shareMood(
                scene: TencentScene.SCENE_QZONE,
                summary: '分享测试',
              );
            },
          ),
          ListTile(
            title: Text('文本分享'),
            onTap: () {
              Tencent.instance.shareText(
                scene: TencentScene.SCENE_QQ,
                summary: '分享测试',
              );
            },
          ),
          ListTile(
            title: Text('图片分享'),
            onTap: () async {
              final File file = await DefaultCacheManager().getSingleFile(
                  'https://www.baidu.com/img/bd_logo1.png?where=super');
              await Tencent.instance.shareImage(
                scene: TencentScene.SCENE_QQ,
                imageUri: Uri.file(file.path),
              );
            },
          ),
          ListTile(
            title: Text('网页分享'),
            onTap: () {
              Tencent.instance.shareWebpage(
                scene: TencentScene.SCENE_QQ,
                title: 'title',
                targetUrl: 'https://www.baidu.com/',
              );
            },
          ),
        ],
      ),
    );
  }

  void _showTips(String title, String content) {
    showDialog<void>(
      context: context,
      builder: (BuildContext context) {
        return AlertDialog(
          title: Text(title),
          content: Text(content),
        );
      },
    );
  }
} 

Download Details:

Author: RxReader

Source Code: https://github.com/RxReader/tencent_kit

#flutter #auth 

A Powerful Flutter Plugin Allowing Developers to Auth/Share

Library Support Navgiation for Authorization Flow on Flutter

auth_nav

A new Flutter package.

Getting Started

This project is a starting point for a Dart package, a library module containing code that can be shared easily across multiple Flutter or Dart projects.

For help getting started with Flutter, view our online documentation, which offers tutorials, samples, guidance on mobile development, and a full API reference.

Use this package as a library

Depend on it

Run this command:

With Flutter:

 $ flutter pub add auth_nav

This will add a line like this to your package's pubspec.yaml (and run an implicit flutter pub get):

dependencies:
  auth_nav: ^2.0.2

Alternatively, your editor might support flutter pub get. Check the docs for your editor to learn more.

Import it

Now in your Dart code, you can use:

import 'package:auth_nav/auth_nav.dart'; 

example/lib/main.dart

import 'package:auth_nav/bloc/auth_navigation_bloc.dart';
import 'package:auth_nav/bloc/auth_navigation_state.dart';
import 'package:auth_nav/navigation/auth_navigation.dart';
import 'package:example/pages/splash_app_page.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:example/pages/authorized_page.dart';
import 'package:example/pages/login_page.dart';

void main() {
  runApp(BlocProvider(
      create: (context) => AuthNavigationBloc(),
      child: MyApp(),
  ));
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      theme: ThemeData.light(),
      home: AuthNavigation(
        splashScreen: SplashAppPage((context) async {
          return Future.delayed(Duration(seconds: 2), () => AuthNavigationState.unAuthorized());
        }),
        authorizedBuilder: (context) => AuthorizedPage(),
        unAuthorizedBuilder: (context) => LoginPage(),
      ),
    );
  }
} 

Download Details:

Author: dangngocduc

Source Code: https://github.com/dangngocduc/auth_nav

#flutter #authorization #auth 

Library Support Navgiation for Authorization Flow on Flutter
Reid  Rohan

Reid Rohan

1661777460

Apple-auth: Sign in with Apple for Node.js

 Sign in with Apple for Node.js

An easy-to-use Node.js library for Signing in with Apple!

Now with support for fetching the name and email!

⚠️ Important note: Apple will only provide you with the name and email ONCE which is when the user taps "Sign in with Apple" on your app the first time. Keep in mind that you have to store this in your database at this time! For every login after that, Apple will provide you with a unique ID that you can use to lookup the username in your database.

Usage

Initialize it using the following code:

const fs = require('fs');
const AppleAuth = require('apple-auth');
const config = fs.readFileSync("./config/config");
const auth = new AppleAuth(config, './config/AuthKey.p8');

Methods:

  • auth.loginURL() - Creates the Login URL that your users will use to login to
  • auth.accessToken(grantCode) - Gets the access token from the grant code received
  • auth.refreshToken(refreshToken) - Gets the access token from a refresh token

Troubleshooting

invalid_grant when authorization code is generated by iOS App

Fix: If the authorizationCode was generated by your app, you should use your App ID as your clientId and not your service one. Discussion: https://github.com/ananay/apple-auth/issues/13

Questions / Contributing

Feel free to open issues and pull requests. If you would like to be one of the core creators of this library, please reach out to me at i@ananayarora.com or message me on twitter @ananayarora!

Created with ❤️ by Ananay Arora

⚠️ Disclaimer

This repository is NOT developed, endorsed by Apple Inc. or even related at all to Apple Inc. This library was implemented solely by the community's hardwork, and based on information that is public on Apple Developer's website. The library is a helper library for anyone trying to implement Apple's Sign in with Apple.


Check out the passport version of this library here:

https://github.com/ananay/passport-apple

https://npmjs.com/package/passport-apple

Setup

Begin by installing the library: npm install apple-auth

The configurations for Sign in with Apple are quite extensive so I've made an extensive SETUP.md file that you can read https://github.com/ananay/apple-auth/blob/master/SETUP.md

Example

I've created an example of how to use this library with Express! Check it out here:

https://github.com/ananay/apple-auth-example

Example live on https://apple.ananay.dev


Download Details:

Author: Ananay
Source Code: https://github.com/ananay/apple-auth 

#javascript #node #apple #auth 

Apple-auth: Sign in with Apple for Node.js

Simple, Customizable Authentication Manager for Flutter

flutter_auth_provider

Simple and extensible authentication manager for apps built with Flutter.

Getting started

Steps

  • Add as a dependency.
  • Implement the Stores.
  • Connect the store to your views.

Concepts

1. Stores

Stores are abstract classes that allow you to implement your custom persistence layer for authentication related data.

You can implement your own authentication persistence logic by implementing the Stores.

  • AuthStore - This is your user related data store. When you implement the AuthStore, you can also use a custom type for a User specified as a generic.
  • TokenStore - Implement how you store and refresh the token.

Example implementation with flutter-secure-storage.

import 'package:flutter_auth_provider/flutter_auth_provider.dart';
import 'package:flutter_secure_storage/flutter_secure_storage.dart';

class User {
  string userName;
  string role;

  const User({ required this.role, required this.userName});
}

const String userNameKey = 'userName';
const String roleKey = 'name';
const String tokenKey = 'token';
const String refreshTokenKey = 'refreshToken';


class SecureStore implements AuthStore<User>, TokenStore {
  static SecureStore _instance = const SecureStore._();
  final FlutterSecureStorage _storage = const FlutterSecureStorage();

  const SecureStore._();

  factory SecureStore() => _instance;

  @override
  Future<void> delete() async {
    await _storage.delete(key: userNameKey);
    await _storage.delete(key: roleKey);
  }

  @override
  Future<User?> retrieve() async {
    final userName = await _storage.read(key: userNameKey);
    final role = await _storage.read(key: roleKey);
    if (userName != null && role != null) {
      return User(userName: userName, role: role);
    }
    return null;
  }

  @override
  Future<void> save(User user) async {
    await _storage.write(key: userNameKey, value: user.userName);
    await _storage.write(key: roleKey, value: user.role);
  }

  @override
  Future<void> clear() async {
    await _storage.delete(key: tokenKey);
    await _storage.delete(key: refreshTokenKey);
  }

  @override
  Future<String?> getRefreshToken() async {
    return _storage.read(key: refreshTokenKey);
  }

  @override
  Future<String?> getToken() async {
    return _storage.read(key: tokenKey);
  }

  @override
  Future<void> saveTokens({required String token, String? refreshToken}) async {
    await _storage.write(key: tokenKey, value: token);
    if (refreshToken != null) {
      await _storage.write(key: refreshTokenKey, value: refreshToken);
    }
  }
}

2. Listeners

There are two listeners available. These will execute your code upon Authentication events.

  • LoginListener - Called when user is logged in.
  • LogoutListener - Called when user logs out.

Examples:

  • Setting up Sentry with user details.
  • Remove/setup/release resources upon logging out.

Contributors

Use this package as a library

Depend on it

Run this command:

With Flutter:

 $ flutter pub add flutter_auth_provider

This will add a line like this to your package's pubspec.yaml (and run an implicit flutter pub get):

dependencies:
  flutter_auth_provider: ^0.1.3

Alternatively, your editor might support flutter pub get. Check the docs for your editor to learn more.

Import it

Now in your Dart code, you can use:

import 'package:flutter_auth_provider/flutter_auth_provider.dart'; 

example/lib/main.dart

import 'package:flutter/material.dart';
import 'package:flutter_auth_provider/flutter_auth_provider.dart';
import 'package:flutter_auth_provider_example/auth/secure_store.dart';
import 'package:flutter_auth_provider_example/auth/type_def.dart';
import 'package:flutter_auth_provider_example/auth/user.dart';
import 'package:flutter_auth_provider_example/auth_app.dart';
import 'package:flutter_auth_provider_example/unauth_app.dart';
import 'package:provider/provider.dart';

void main() {
  runApp(
    AuthProvider<User>(
      store: SecureStore(),
      child: const MyApp(),
    ),
  );
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    final bool isAuthenticated = context.watch<MyAuthManager>().isLoggedIn;
    if (isAuthenticated) {
      return const AuthenticatedApp();
    } else {
      return const UnAuthenticatedApp();
    }
  }
} 

Download Details:

Author: iamchathu

Source Code: https://github.com/iamchathu/flutter_auth_provider

#flutter #auth #management 

Simple, Customizable Authentication Manager for Flutter
Minh  Nguyet

Minh Nguyet

1661171640

Cách Triển Khai Xác Thực Facebook Cho ứng Dụng Flutter

Xác thực là một quá trình bảo mật, theo đó người dùng phải cung cấp danh tính của họ để truy cập vào một ứng dụng, hệ thống cụ thể hoặc một phần thông tin hoặc tài nguyên cụ thể. Về bảo mật máy tính, xác thực là quá trình hoặc hành động xác minh danh tính của người dùng. Nếu không có xác thực, các mạng máy tính luôn sẵn sàng cho các cuộc tấn công và một tin tặc có thể muốn truy cập vào thông tin hoặc tài nguyên bí mật.

Flutter cung cấp cho chúng tôi một gói được gọi là flutter_facebook_auth, nơi chúng tôi có thể dễ dàng thêm thông tin đăng nhập Facebook vào ứng dụng Flutter của mình. Nó cung cấp cho chúng tôi rất nhiều tính năng bao gồm:

  • Đăng nhập trên IOS, Android và Web
  • Đăng nhập nhanh trên Android
  • Cung cấp mã thông báo truy cập để thực hiện yêu cầu đối với API Đồ thị và hơn thế nữa.

Để có tài liệu đầy đủ, hãy truy cập trang này .

Trong bài viết này, chúng tôi sẽ thiết lập một ứng dụng để hướng dẫn cách sử dụng gói này trong ứng dụng Flutter của chúng tôi.

Tạo ứng dụng Flutter của chúng tôi

Để bắt đầu, hãy truy cập GitHub và sao chép các tệp khởi động được tạo cho dự án này. Mở pubspec.yamltệp và thêm flutter_facebook_authdưới cupertino_iconshoặc chạy flutter pub add flutter_facebook_authtrên thiết bị đầu cuối của bạn.

name: facebook_auth
description: A new Flutter project.

publish_to: `none 

version: 1.0.0+1

environment:
  sdk: ">=2.17.6 <3.0.0"

dependencies:
  flutter:
    sdk: flutter

  cupertino_icons: ^1.0.2
  flutter_facebook_auth: ^4.4.0+1 # Add This Line

dev_dependencies:
  flutter_test:
    sdk: flutter

  flutter_lints: ^2.0.0

flutter:
  uses-material-design: true

Thêm phụ thuộc vào ứng dụng của chúng tôi

Trước khi thêm các chức năng vào ứng dụng của mình, chúng tôi cần định cấu hình các tệp gốc của dự án để cấp cho chúng tôi quyền truy cập Đăng nhập Facebook. Trên trình duyệt của bạn, hãy truy cập Nhà phát triển Facebook để tạo Tài khoản nhà phát triển Facebook và bắt đầu tạo ứng dụng của chúng tôi.

1

Bấm vào nút đăng nhập. Thao tác này sẽ nhắc bạn đăng nhập bằng thông tin chi tiết Facebook của bạn.

2

Nhập chi tiết đăng nhập của bạn và nhấn nút Đăng nhập để tiếp tục.

3

Nhấp vào My Appsvà chúng tôi có thể bắt đầu tạo ứng dụng của mình trên Facebook.

4

Ở đây chúng tôi không có ứng dụng nào được tạo. Nhấn vào nút Tạo ứng dụng để chúng tôi có thể bắt đầu tạo ứng dụng của mình

5

Tại đây, chúng tôi có thể chọn bất kỳ loại ứng dụng nào. Tôi sẽ chọn Doanh nghiệp cho hướng dẫn này và nhấn Tiếp theo.

6

Thêm tên hiển thị mà bạn chọn và nhấn tạo ứng dụng để tiếp tục. Bạn có thể được nhắc nhập mật khẩu, nhập mật khẩu và nhấp vào Gửi.

7

Ở đây bạn có thể thấy rằng ứng dụng của chúng tôi đã được tạo. Chúng tôi có tên ứng dụng của chúng tôi ở trên cùng bên trái và id ứng dụng của chúng tôi. Nhấp vào Facebook Loginđể chúng tôi có thể thiết lập tính năng đăng nhập Facebook trên ứng dụng của mình.

8

Tôi sẽ làm việc trên nền tảng Android cho hướng dẫn này. Nhấp vào biểu tượng Android để tiếp tục.

9

Trong project-level > build.gradletệp của bạn, hãy thêm mã vàobuildscript{repositories{ }}

buildscript {
    ext.kotlin_version = '1.6.10'
    repositories {
        google()
        mavenCentral() // Add Here
    }

    dependencies {
        classpath 'com.android.tools.build:gradle:7.1.2'
        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
    }
}

allprojects {
    repositories {
        google()
        mavenCentral() // Add Here
    }
}

rootProject.buildDir = '../build'
subprojects {
    project.buildDir = "${rootProject.buildDir}/${project.name}"
}
subprojects {
    project.evaluationDependsOn(':app')
}

task clean(type: Delete) {
    delete rootProject.buildDir
}

Và trong app-level>build.gradletệp của bạn, hãy thêm mã vào phần phụ thuộc.

def localProperties = new Properties()
def localPropertiesFile = rootProject.file('local.properties')
if (localPropertiesFile.exists()) {
    localPropertiesFile.withReader('UTF-8') { reader ->
        localProperties.load(reader)
    }
}

def flutterRoot = localProperties.getProperty('flutter.sdk')
if (flutterRoot == null) {
    throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.")
}

def flutterVersionCode = localProperties.getProperty('flutter.versionCode')
if (flutterVersionCode == null) {
    flutterVersionCode = '1'
}

def flutterVersionName = localProperties.getProperty('flutter.versionName')
if (flutterVersionName == null) {
    flutterVersionName = '1.0'
}

apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"

android {
    compileSdkVersion flutter.compileSdkVersion
    ndkVersion flutter.ndkVersion

    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }

    kotlinOptions {
        jvmTarget = '1.8'
    }

    sourceSets {
        main.java.srcDirs += 'src/main/kotlin'
    }

    defaultConfig {
        // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
        applicationId "com.example.facebook_auth"
        // You can update the following values to match your application needs.
        // For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-build-configuration.
        minSdkVersion flutter.minSdkVersion
        targetSdkVersion flutter.targetSdkVersion
        versionCode flutterVersionCode.toInteger()
        versionName flutterVersionName
    }

    buildTypes {
        release {
            // TODO: Add your own signing config for the release build.
            // Signing with the debug keys for now, so `flutter run --release` works.
            signingConfig signingConfigs.debug
        }
    }
}

flutter {
    source '../..'
}

dependencies {
    implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
    implementation 'com.facebook.android:facebook-android-sdk:latest.release' // Add This Line Here.
}

Nhấp vào Tiếp theo Nếu bạn đã làm điều đó thành công.

10

Trong bước 3, nhập Package NameDefault Activity Class Namenhư đã thấy ở trên. Bạn có thể lấy tên gói của mình bằng cách truy cập android>app>build.gradletệp trong dự án Flutter của bạn.

Nhấn Lưu để tiếp tục thiết lập ứng dụng.

11

Ở bước 4, chúng ta cần tạo một mã băm khóa phát triển để đảm bảo tính xác thực của tương tác giữa ứng dụng của chúng ta và Facebook. Tôi đang sử dụng máy windows, vì vậy tôi sẽ nhấp vào openssl-for-windowsvà tải xuống và giải nén tệp zip dành riêng cho PC của tôi (32bit hoặc 64bit). Sao chép mã bên dưới và dán vào thiết bị đầu cuối của bạn.

keytool -exportcert -alias androiddebugkey -keystore "C:\Users\USERNAME\.android\debug.keystore" | "PATH_TO_OPENSSL_LIBRARY\bin\openssl" sha1 -binary | "PATH_TO_OPENSSL_LIBRARY\bin\openssl" base64

Thay đổi USERNAME thành của riêng bạn và thêm đường dẫn đến openss\binthư mục. Trong trường hợp của tôi, tôi có cái này:

12

Ở đây, tôi đã thay đổi tên người dùng thành người dùng hệ thống của mình và thêm đường dẫn đến openssl\binthư mục. Khi được nhắc nhập mật khẩu, hãy sử dụng android. Thao tác này sẽ tạo ra một khóa để bạn sao chép và dán vào phần Key Hashes trên trang web của bạn.

14

Nhấn Lưu và Tiếp tục.

14

Bước 5, kích hoạt đăng nhập một lần, nhấp vào Lưu và Tiếp theo.

15

Trong Bước 6, chúng tôi sẽ chỉnh sửa tệp Tài nguyên và Tệp kê khai. Trên của bạn app>src>main>res>values, hãy tạo một string.xmltệp và thêm mã bên dưới:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string name="app_name">App Name</string>
    <string name="facebook_app_id">App ID</string>
    <string name="fb_login_protocol_scheme">Login Protocol Scheme</string>
    <string name="facebook_client_token">Client Token</string>
</resources>

Của bạn facebook_app_idcó thể được tìm thấy ở trên trong trình duyệt của bạn và của bạn fb_login_protocol_schemelà id ứng dụng của bạn với tiền tố fb(ví dụ: nếu Id ứng dụng của bạn là 1234, lược đồ giao thức của bạn sẽ là fb1234). Để có được facebook_client_token, trên trang tổng quan của bạn, hãy điều hướng đến Settings>Advanced>Security>Client Token. Trong trường hợp của tôi:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string name="app_name">Auth Tutorial</string>
    <string name="facebook_app_id">1924520271082903</string>
    <string name="fb_login_protocol_scheme">fb1924520271082903</string>
    <string name="facebook_client_token">ab808c0a71a13009bcf8792433ff6b94</string>
</resources>

Cuối cùng, hãy truy cập AndroidManifest.xmltệp của bạn và sao chép mã bên dưới:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.facebook_auth">
    
    <!-- FACEBOOK CONFIGURATIONS -->
    <uses-permission android:name="android.permission.INTERNET"/>
    <!-- FACEBOOK CONFIGURATIONS ENDS HERE -->  


    <application
        android:label="facebook_auth"
        android:name="${applicationName}"
        android:icon="@mipmap/ic_launcher">
        <activity
            android:name=".MainActivity"
            android:exported="true"
            android:launchMode="singleTop"
            android:theme="@style/LaunchTheme"
            android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
            android:hardwareAccelerated="true"
            android:windowSoftInputMode="adjustResize">
            <meta-data
              android:name="io.flutter.embedding.android.NormalTheme"
              android:resource="@style/NormalTheme"
              />
            <intent-filter>
                <action android:name="android.intent.action.MAIN"/>
                <category android:name="android.intent.category.LAUNCHER"/>
            </intent-filter>
        </activity>
        <meta-data
            android:name="flutterEmbedding"
            android:value="2" />
        
            <!-- FACEBOOK CONFIGURATIONS -->
        <meta-data android:name="com.facebook.sdk.ApplicationId" android:value="@string/facebook_app_id"/>
        <meta-data android:name="com.facebook.sdk.ClientToken" android:value="@string/facebook_client_token"/>

        <activity android:name="com.facebook.FacebookActivity"
            android:configChanges=
                "keyboard|keyboardHidden|screenLayout|screenSize|orientation"
            android:label="@string/app_name" />
        <activity
            android:name="com.facebook.CustomTabActivity"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.VIEW" />
                <category android:name="android.intent.category.DEFAULT" />
                <category android:name="android.intent.category.BROWSABLE" />
                <data android:scheme="@string/fb_login_protocol_scheme" />
            </intent-filter>
        </activity>
        <!--FACEBOOK CONFIGURATION ENDS HERE -->
    </application>
</manifest>

Lưu ý: Tôi đã nhận xét những dòng bạn muốn sao chép và dán. Bạn đã hoàn thành tất cả các nhiệm vụ liên quan đến Facebook. Tiếp theo, chúng tôi sẽ bắt đầu thêm chức năng vào ứng dụng của mình.

Thêm các chức năng

Với cấu hình nền tảng hoàn tất, hãy thiết lập ứng dụng của chúng tôi. Trong tệp main.dart của chúng tôi, chúng tôi sẽ thêm các chức năng vào nút của chúng tôi. Trên onPressedtham số, thêm mã bên dưới.

Navigator.push(
                context,
                MaterialPageRoute(
                  builder: (context) => const UserScreen(),
                ),
              );

Đoạn mã trên cho phép chúng ta chuyển sang màn hình tiếp theo (sự UserScreen()) khi nút được nhấp. Tạo một tệp phi tiêu mới có tên user_screen.dartbên trong thư mục lib. Tệp này sẽ được sử dụng để hiển thị dữ liệu người dùng nhận được từ Facebook.

// user.dart

import 'package:flutter/material.dart';
import 'package:flutter_facebook_auth/flutter_facebook_auth.dart';

class UserScreen extends StatefulWidget {
  const UserScreen({Key? key}) : super(key: key);

  @override
  State<UserScreen> createState() => _UserScreenState();
}

class _UserScreenState extends State<UserScreen> {
  Map<String, dynamic>? _userData;
  AccessToken? _accessToken;
  bool? _checking = true;

  _ifUserIsLoggedIn() async {
    final accessToken = await FacebookAuth.instance.accessToken;

    setState(() {
      _checking = false;
    });

    if (accessToken != null) {
      final userData = await FacebookAuth.instance.getUserData();
      _accessToken = accessToken;
      setState(() {
        _userData = userData;
      });
    } else {
      _login();
    }
  }

  _login() async {
    final LoginResult loginResult = await FacebookAuth.instance.login();

    if (loginResult.status == LoginStatus.success) {
      _accessToken = loginResult.accessToken;
      final userInfo = await FacebookAuth.instance.getUserData();
      _userData = userInfo;
    } else {
      print('ResultStatus: ${loginResult.status}');
      print('Message: ${loginResult.message}');
    }
  }

  _logOut() async {
    await FacebookAuth.instance.logOut();
    _accessToken = null;
    _userData = null;
  }

  @override
  void initState() {
    super.initState();
    _ifUserIsLoggedIn();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        body: _checking!
            ? const Center(
                child: CircularProgressIndicator(),
              )
            : Center(
                child: Column(
                  mainAxisAlignment: MainAxisAlignment.center,
                  crossAxisAlignment: CrossAxisAlignment.center,
                  children: [
                    const Text('Welcome'),
                    _userData != null
                        ? Text(
                            '${_userData!['name']}',
                            style: TextStyle(
                                fontWeight: FontWeight.bold, fontSize: 28),
                          )
                        : Container(),
                    _userData != null
                        ? Container(
                            child: Image.network(
                                _userData!\['picture'\]['data']['url']),
                          )
                        : Container(),
                    const SizedBox(
                      height: 20,
                    ),
                    ElevatedButton(
                      onPressed: () {
                        _logOut();
                        Navigator.pop(context);
                      },
                      child: const Text('Log Out'),
                    ),
                  ],
                ),
              ));
  }
}

Hãy để chúng tôi chia nhỏ đoạn mã trên.

Map<String, dynamic>? _userData;
  AccessToken? _accessToken;
  bool? _checking = true;

Trong đoạn mã trên, chúng ta có ba biến nullable:

  • _userData: Điều này giữ thông tin người dùng khi đăng nhập.
  • _accessToken: Khi đăng nhập, mã thông báo truy cập sẽ được tạo tự động; biến này sẽ giữ mã thông báo truy cập đó cho chúng tôi.
  • _checking: Điều này kiểm tra xem người dùng đã đăng nhập trước đó hay chưa.
_ifUserIsLoggedIn() async {
    final accessToken = await FacebookAuth.instance.accessToken;

    setState(() {
      _checking = false;
    });

    if (accessToken != null) {
      final userData = await FacebookAuth.instance.getUserData();
      _accessToken = accessToken;
      setState(() {
        _userData = userData;
      });
    } else {
      _login();
    }
  }

  _login() async {
    final LoginResult loginResult = await FacebookAuth.instance.login();

    if (loginResult.status == LoginStatus.success) {
      _accessToken = loginResult.accessToken;
      final userInfo = await FacebookAuth.instance.getUserData();
      _userData = userInfo;
    } else {
      print('ResultStatus: ${loginResult.status}');
      print('Message: ${loginResult.message}');
    }
  }

  _logOut() async {
    await FacebookAuth.instance.logOut();
    _accessToken = null;
    _userData = null;
  }

Nhìn vào đoạn mã trên, chúng ta có ba hàm không đồng bộ:

  • _ifUserIsLoggedIn(): Điều này kiểm tra xem người dùng đã đăng nhập và nhận được mã thông báo truy cập và dữ liệu người dùng hay chưa.
  • _login(): Chức năng đăng nhập cho phép chúng tôi đăng nhập và nếu trạng thái đăng nhập thành công, nó sẽ nhận được dữ liệu người dùng và mã thông báo truy cập được tạo.
  • _logOut(): Điều này đặt dữ liệu người dùng và mã thông báo truy cập thành null và sau đó đưa chúng ta trở lại trang đầu tiên.
Scaffold(
        body: _checking!
            ? const Center(
                child: CircularProgressIndicator(),
              )
            : Center(
                child: Column(
                  mainAxisAlignment: MainAxisAlignment.center,
                  crossAxisAlignment: CrossAxisAlignment.center,
                  children: [
                    const Text('Welcome'),
                    _userData != null
                        ? Text(
                            '${_userData!['name']}',
                            style: TextStyle(
                                fontWeight: FontWeight.bold, fontSize: 28),
                          )
                        : Container(),
                    _userData != null
                        ? Container(
                            child: Image.network(
                                _userData!\['picture'\]['data']['url']),
                          )
                        : Container(),
                    const SizedBox(
                      height: 20,
                    ),
                    ElevatedButton(
                      onPressed: () {
                        _logOut();
                        Navigator.pop(context);
                      },
                      child: const Text('Log Out'),
                    ),
                  ],
                ),
              ));

Đoạn mã trên hiển thị các giá trị của chúng tôi trên màn hình. Chúng tôi sử dụng toán tử bậc ba, là một câu lệnh if và else được đơn giản hóa trong dart. Nó kiểm tra xem giá trị của biến _checkingcó đúng không, sau đó hiển thị chỉ báo tiến trình; khác, hiển thị dữ liệu người dùng. Chúng tôi cũng có một nút đăng xuất có _logOutchức năng này và đưa chúng tôi trở lại màn hình chính.

Kiểm tra ứng dụng

Với tất cả cấu hình và thiết lập hoàn tất, hãy thử nghiệm ứng dụng của chúng tôi. Chạy ứng dụng trên trình giả lập hoặc thiết bị thực tế bằng lệnh trong thiết bị đầu cuối. Lệnh flutter runsẽ xây dựng ứng dụng và cài đặt nó trên thiết bị của bạn.

video

Sự kết luận

Xác thực là cần thiết cho ứng dụng của chúng tôi. Nếu không có nó, bạn giữ cho dữ liệu dễ bị vi phạm và truy cập trái phép.

Liên kết: https://blog.openreplay.com/implecting-facebook-authentication-for-flutter

#flutter #auth

Cách Triển Khai Xác Thực Facebook Cho ứng Dụng Flutter

Как реализовать аутентификацию Facebook для приложения Flutter

Аутентификация — это процесс безопасности, при котором пользователь должен указать свою личность для доступа к определенному приложению, системе или части определенной информации или ресурса. С точки зрения компьютерной безопасности аутентификация — это процесс или действие по проверке личности пользователя. Без аутентификации компьютерные сети открыты для атак, и хакер может захотеть получить доступ к конфиденциальной информации или ресурсам.

Flutter предоставляет нам пакет, известный как flutter_facebook_auth, где мы можем легко добавить логин Facebook в наше приложение Flutter. Он предоставляет нам множество функций, которые включают в себя:

  • Вход на IOS, Android и в Интернете
  • Экспресс-вход на Android
  • Предоставьте токен доступа, чтобы сделать запрос к API Graph и многое другое.

Для получения полной документации перейдите на эту страницу .

В этой статье мы настроим приложение, чтобы показать, как использовать этот пакет в нашем приложении Flutter.

Создание нашего приложения Flutter

Для начала перейдите на GitHub и клонируйте начальные файлы, созданные для этого проекта. Откройте pubspec.yamlфайл и добавьте flutter_facebook_authпод cupertino_iconsили запустите flutter pub add flutter_facebook_authна своем терминале.

name: facebook_auth
description: A new Flutter project.

publish_to: `none 

version: 1.0.0+1

environment:
  sdk: ">=2.17.6 <3.0.0"

dependencies:
  flutter:
    sdk: flutter

  cupertino_icons: ^1.0.2
  flutter_facebook_auth: ^4.4.0+1 # Add This Line

dev_dependencies:
  flutter_test:
    sdk: flutter

  flutter_lints: ^2.0.0

flutter:
  uses-material-design: true

Добавление зависимостей в наше приложение

Прежде чем добавлять функции в наше приложение, нам нужно настроить корневые файлы проекта, чтобы предоставить нам доступ к входу в Facebook. В своем браузере перейдите в Facebook Developer , чтобы создать учетную запись разработчика Facebook и начать создавать наше приложение.

первый

Нажмите кнопку входа. Вам будет предложено войти в систему, используя свои данные Facebook.

2

Введите свои данные для входа и нажмите кнопку «Войти», чтобы продолжить.

3

Нажмите My Apps, и мы можем приступить к созданию нашего приложения на Facebook.

4

Здесь у нас нет созданного приложения. Нажмите кнопку «Создать приложение», чтобы мы могли начать создавать наше приложение.

5

Здесь мы можем выбрать любой тип приложения. Я собираюсь выбрать Business для этого урока и нажать Next.

6

Добавьте отображаемое имя по вашему выбору и нажмите «Создать приложение», чтобы продолжить. Вам может быть предложено ввести пароль, введите пароль и нажмите «Отправить».

7

Здесь вы можете увидеть, что наше приложение создано. У нас есть имя нашего приложения в левом верхнем углу и идентификатор нашего приложения. Нажмите, Facebook Loginчтобы мы могли настроить функцию входа в Facebook в нашем приложении.

8

Для этого урока я буду работать на платформе Android. Нажмите на логотип Android, чтобы продолжить.

9

В вашем project-level > build.gradleфайле добавьте код вbuildscript{repositories{ }}

buildscript {
    ext.kotlin_version = '1.6.10'
    repositories {
        google()
        mavenCentral() // Add Here
    }

    dependencies {
        classpath 'com.android.tools.build:gradle:7.1.2'
        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
    }
}

allprojects {
    repositories {
        google()
        mavenCentral() // Add Here
    }
}

rootProject.buildDir = '../build'
subprojects {
    project.buildDir = "${rootProject.buildDir}/${project.name}"
}
subprojects {
    project.evaluationDependsOn(':app')
}

task clean(type: Delete) {
    delete rootProject.buildDir
}

И в своем app-level>build.gradleфайле добавьте код в раздел зависимостей.

def localProperties = new Properties()
def localPropertiesFile = rootProject.file('local.properties')
if (localPropertiesFile.exists()) {
    localPropertiesFile.withReader('UTF-8') { reader ->
        localProperties.load(reader)
    }
}

def flutterRoot = localProperties.getProperty('flutter.sdk')
if (flutterRoot == null) {
    throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.")
}

def flutterVersionCode = localProperties.getProperty('flutter.versionCode')
if (flutterVersionCode == null) {
    flutterVersionCode = '1'
}

def flutterVersionName = localProperties.getProperty('flutter.versionName')
if (flutterVersionName == null) {
    flutterVersionName = '1.0'
}

apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"

android {
    compileSdkVersion flutter.compileSdkVersion
    ndkVersion flutter.ndkVersion

    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }

    kotlinOptions {
        jvmTarget = '1.8'
    }

    sourceSets {
        main.java.srcDirs += 'src/main/kotlin'
    }

    defaultConfig {
        // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
        applicationId "com.example.facebook_auth"
        // You can update the following values to match your application needs.
        // For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-build-configuration.
        minSdkVersion flutter.minSdkVersion
        targetSdkVersion flutter.targetSdkVersion
        versionCode flutterVersionCode.toInteger()
        versionName flutterVersionName
    }

    buildTypes {
        release {
            // TODO: Add your own signing config for the release build.
            // Signing with the debug keys for now, so `flutter run --release` works.
            signingConfig signingConfigs.debug
        }
    }
}

flutter {
    source '../..'
}

dependencies {
    implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
    implementation 'com.facebook.android:facebook-android-sdk:latest.release' // Add This Line Here.
}

Нажмите «Далее», если вы сделали это успешно.

10

На шаге 3 введите Package Nameи , Default Activity Class Nameкак показано выше. Вы можете получить имя своего пакета, перейдя к своему android>app>build.gradleфайлу в своем проекте Flutter.

Нажмите «Сохранить», чтобы продолжить настройку приложения.

11

На шаге 4 нам нужно сгенерировать хэш ключа разработки, чтобы обеспечить подлинность взаимодействия между нашим приложением и Facebook. Я нахожусь на компьютере с Windows, поэтому я нажму openssl-for-windowsи загружу и извлеку zip-файл, специфичный для моего ПК (32-битный или 64-битный). Скопируйте приведенный ниже код и вставьте его в свой терминал.

keytool -exportcert -alias androiddebugkey -keystore "C:\Users\USERNAME\.android\debug.keystore" | "PATH_TO_OPENSSL_LIBRARY\bin\openssl" sha1 -binary | "PATH_TO_OPENSSL_LIBRARY\bin\openssl" base64

Измените ИМЯ ПОЛЬЗОВАТЕЛЯ на свое и добавьте путь к openss\binпапке. В моем случае у меня это:

двенадцатый

Здесь я изменил имя пользователя на своего системного пользователя и добавил путь к openssl\binпапке. Когда будет предложено ввести пароль, используйте android. Это создаст ключ, который вы сможете скопировать и вставить в раздел Key Hashes на своей веб-странице.

14

Нажмите «Сохранить и продолжить».

14

Шаг 5, включите единый вход, нажмите «Сохранить» и «Далее».

15

На шаге 6 мы отредактируем файл ресурсов и манифеста. На вашем app>src>main>res>values, создайте string.xmlфайл и добавьте код ниже:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string name="app_name">App Name</string>
    <string name="facebook_app_id">App ID</string>
    <string name="fb_login_protocol_scheme">Login Protocol Scheme</string>
    <string name="facebook_client_token">Client Token</string>
</resources>

Ваш facebook_app_idможно найти выше в вашем браузере, и fb_login_protocol_schemeваш идентификатор вашего приложения с префиксом fb(например, если ваш идентификатор приложения 1234, ваша схема протокола будет fb1234). Чтобы получить свой facebook_client_token, на панели инструментов перейдите к Settings>Advanced>Security>Client Token. В моем случае:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string name="app_name">Auth Tutorial</string>
    <string name="facebook_app_id">1924520271082903</string>
    <string name="fb_login_protocol_scheme">fb1924520271082903</string>
    <string name="facebook_client_token">ab808c0a71a13009bcf8792433ff6b94</string>
</resources>

Наконец, перейдите в свой AndroidManifest.xmlфайл и скопируйте код ниже:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.facebook_auth">
    
    <!-- FACEBOOK CONFIGURATIONS -->
    <uses-permission android:name="android.permission.INTERNET"/>
    <!-- FACEBOOK CONFIGURATIONS ENDS HERE -->  


    <application
        android:label="facebook_auth"
        android:name="${applicationName}"
        android:icon="@mipmap/ic_launcher">
        <activity
            android:name=".MainActivity"
            android:exported="true"
            android:launchMode="singleTop"
            android:theme="@style/LaunchTheme"
            android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
            android:hardwareAccelerated="true"
            android:windowSoftInputMode="adjustResize">
            <meta-data
              android:name="io.flutter.embedding.android.NormalTheme"
              android:resource="@style/NormalTheme"
              />
            <intent-filter>
                <action android:name="android.intent.action.MAIN"/>
                <category android:name="android.intent.category.LAUNCHER"/>
            </intent-filter>
        </activity>
        <meta-data
            android:name="flutterEmbedding"
            android:value="2" />
        
            <!-- FACEBOOK CONFIGURATIONS -->
        <meta-data android:name="com.facebook.sdk.ApplicationId" android:value="@string/facebook_app_id"/>
        <meta-data android:name="com.facebook.sdk.ClientToken" android:value="@string/facebook_client_token"/>

        <activity android:name="com.facebook.FacebookActivity"
            android:configChanges=
                "keyboard|keyboardHidden|screenLayout|screenSize|orientation"
            android:label="@string/app_name" />
        <activity
            android:name="com.facebook.CustomTabActivity"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.VIEW" />
                <category android:name="android.intent.category.DEFAULT" />
                <category android:name="android.intent.category.BROWSABLE" />
                <data android:scheme="@string/fb_login_protocol_scheme" />
            </intent-filter>
        </activity>
        <!--FACEBOOK CONFIGURATION ENDS HERE -->
    </application>
</manifest>

Примечание. Я прокомментировал строки, которые вы должны скопировать и вставить. Вы выполнили все задания, связанные с Facebook. Далее мы начнем добавлять функциональность в наше приложение.

Добавление функций

Когда конфигурация платформы завершена, давайте настроим наше приложение. В нашем файле main.dart мы добавим функции к нашей кнопке. В onPressedпараметре добавьте приведенный ниже код.

Navigator.push(
                context,
                MaterialPageRoute(
                  builder: (context) => const UserScreen(),
                ),
              );

Приведенный выше код позволяет нам перейти к следующему экрану ( UserScreen()) при нажатии кнопки. Создайте новый файл дротика с именем user_screen.dartвнутри папки lib. Этот файл будет использоваться для отображения пользовательских данных, полученных от Facebook.

// user.dart

import 'package:flutter/material.dart';
import 'package:flutter_facebook_auth/flutter_facebook_auth.dart';

class UserScreen extends StatefulWidget {
  const UserScreen({Key? key}) : super(key: key);

  @override
  State<UserScreen> createState() => _UserScreenState();
}

class _UserScreenState extends State<UserScreen> {
  Map<String, dynamic>? _userData;
  AccessToken? _accessToken;
  bool? _checking = true;

  _ifUserIsLoggedIn() async {
    final accessToken = await FacebookAuth.instance.accessToken;

    setState(() {
      _checking = false;
    });

    if (accessToken != null) {
      final userData = await FacebookAuth.instance.getUserData();
      _accessToken = accessToken;
      setState(() {
        _userData = userData;
      });
    } else {
      _login();
    }
  }

  _login() async {
    final LoginResult loginResult = await FacebookAuth.instance.login();

    if (loginResult.status == LoginStatus.success) {
      _accessToken = loginResult.accessToken;
      final userInfo = await FacebookAuth.instance.getUserData();
      _userData = userInfo;
    } else {
      print('ResultStatus: ${loginResult.status}');
      print('Message: ${loginResult.message}');
    }
  }

  _logOut() async {
    await FacebookAuth.instance.logOut();
    _accessToken = null;
    _userData = null;
  }

  @override
  void initState() {
    super.initState();
    _ifUserIsLoggedIn();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        body: _checking!
            ? const Center(
                child: CircularProgressIndicator(),
              )
            : Center(
                child: Column(
                  mainAxisAlignment: MainAxisAlignment.center,
                  crossAxisAlignment: CrossAxisAlignment.center,
                  children: [
                    const Text('Welcome'),
                    _userData != null
                        ? Text(
                            '${_userData!['name']}',
                            style: TextStyle(
                                fontWeight: FontWeight.bold, fontSize: 28),
                          )
                        : Container(),
                    _userData != null
                        ? Container(
                            child: Image.network(
                                _userData!\['picture'\]['data']['url']),
                          )
                        : Container(),
                    const SizedBox(
                      height: 20,
                    ),
                    ElevatedButton(
                      onPressed: () {
                        _logOut();
                        Navigator.pop(context);
                      },
                      child: const Text('Log Out'),
                    ),
                  ],
                ),
              ));
  }
}

Давайте разберем приведенный выше код.

Map<String, dynamic>? _userData;
  AccessToken? _accessToken;
  bool? _checking = true;

В приведенном выше коде у нас есть три обнуляемые переменные:

  • _userData: содержит информацию о пользователе при входе в систему.
  • _accessToken: при входе в систему автоматически создается токен доступа; эта переменная будет содержать этот токен доступа для нас.
  • _checking: Это проверяет, вошел ли пользователь в систему раньше или нет.
_ifUserIsLoggedIn() async {
    final accessToken = await FacebookAuth.instance.accessToken;

    setState(() {
      _checking = false;
    });

    if (accessToken != null) {
      final userData = await FacebookAuth.instance.getUserData();
      _accessToken = accessToken;
      setState(() {
        _userData = userData;
      });
    } else {
      _login();
    }
  }

  _login() async {
    final LoginResult loginResult = await FacebookAuth.instance.login();

    if (loginResult.status == LoginStatus.success) {
      _accessToken = loginResult.accessToken;
      final userInfo = await FacebookAuth.instance.getUserData();
      _userData = userInfo;
    } else {
      print('ResultStatus: ${loginResult.status}');
      print('Message: ${loginResult.message}');
    }
  }

  _logOut() async {
    await FacebookAuth.instance.logOut();
    _accessToken = null;
    _userData = null;
  }

Глядя на код выше, у нас есть три асинхронные функции:

  • _ifUserIsLoggedIn(): это проверяет, вошел ли пользователь в систему и получает токен доступа и данные пользователя.
  • _login(): функция входа заставляет нас войти в систему, и если статус входа был успешным, он должен получить данные пользователя и сгенерированный токен доступа.
  • _logOut(): это устанавливает пользовательские данные и токен доступа в ноль, а затем возвращает нас на первую страницу.
Scaffold(
        body: _checking!
            ? const Center(
                child: CircularProgressIndicator(),
              )
            : Center(
                child: Column(
                  mainAxisAlignment: MainAxisAlignment.center,
                  crossAxisAlignment: CrossAxisAlignment.center,
                  children: [
                    const Text('Welcome'),
                    _userData != null
                        ? Text(
                            '${_userData!['name']}',
                            style: TextStyle(
                                fontWeight: FontWeight.bold, fontSize: 28),
                          )
                        : Container(),
                    _userData != null
                        ? Container(
                            child: Image.network(
                                _userData!\['picture'\]['data']['url']),
                          )
                        : Container(),
                    const SizedBox(
                      height: 20,
                    ),
                    ElevatedButton(
                      onPressed: () {
                        _logOut();
                        Navigator.pop(context);
                      },
                      child: const Text('Log Out'),
                    ),
                  ],
                ),
              ));

Приведенный выше код отображает наши значения на экране. Мы используем тернарный оператор, который является упрощенным оператором if и else в dart. Он проверяет, является ли значение переменной _checkingистинным, а затем отображает индикатор выполнения; в противном случае отобразите пользовательские данные. У нас также есть кнопка выхода из системы, которая выполняет _logOutфункцию и возвращает нас на главный экран.

Тестирование приложения

Когда все настройки и настройки завершены, давайте протестируем наше приложение. Запустите приложение на эмуляторе или реальном устройстве, используя команду в терминале. Команда flutter runсоздаст приложение и установит его на ваше устройство.

видео

Вывод

Аутентификация необходима для нашего приложения. Без него вы сохраняете данные уязвимыми для взломов и несанкционированного доступа.

Ссылка: https://blog.openreplay.com/implementing-facebook-authentication-for-flutter

#flutter #auth

Как реализовать аутентификацию Facebook для приложения Flutter
山田  千代

山田 千代

1661157147

如何為 Flutter 應用實現 Facebook 身份驗證

身份驗證是一個安全過程,用戶必須提供他們的身份才能訪問特定的應用程序、系統或一段特定的信息或資源。在計算機安全方面,身份驗證是驗證用戶身份的過程或動作。如果沒有身份驗證,計算機網絡就容易受到攻擊,黑客可能想要獲得對機密信息或資源的訪問權限。

Flutter為我們提供了一個名為 的包flutter_facebook_auth,我們可以在其中輕鬆地將 Facebook 登錄添加到我們的 Flutter 應用程序中。它為我們提供了很多功能,包括:

  • 在 IOS、Android 和 Web 上登錄
  • 在 Android 上快速登錄
  • 提供訪問令牌以向 Graph API 發出請求等等。

如需完整文檔,請訪問此頁面

在本文中,我們將設置一個應用程序來展示如何在我們的 Flutter 應用程序中使用這個包。

創建我們的 Flutter 應用程序

要開始,請前往GitHub並克隆為此項目創建的啟動文件。打開pubspec.yaml文件並在終端flutter_facebook_auth下添加cupertino_icons或運行flutter pub add flutter_facebook_auth

name: facebook_auth
description: A new Flutter project.

publish_to: `none 

version: 1.0.0+1

environment:
  sdk: ">=2.17.6 <3.0.0"

dependencies:
  flutter:
    sdk: flutter

  cupertino_icons: ^1.0.2
  flutter_facebook_auth: ^4.4.0+1 # Add This Line

dev_dependencies:
  flutter_test:
    sdk: flutter

  flutter_lints: ^2.0.0

flutter:
  uses-material-design: true

向我們的應用程序添加依賴項

在向我們的應用程序添加功能之前,我們需要配置項目根文件以授予我們訪問 Facebook 登錄的權限。在您的瀏覽器上,前往Facebook 開發者創建一個 Facebook 開發者帳戶並開始創建我們的應用程序。

第一的

單擊登錄按鈕。這將提示您使用您的 Facebook 詳細信息登錄。

2

輸入您的登錄詳細信息,然後點擊登錄按鈕繼續。

3

點擊My Apps,我們就可以開始在 Facebook 上創建我們的應用了。

4

在這裡,我們沒有創建應用程序。點擊 Create App 按鈕,這樣我們就可以開始創建我們的應用程序了

5

在這裡,我們可以選擇任何應用類型。我將為本教程選擇業務並點擊下一步。

6

添加您選擇的顯示名稱,然後點擊創建應用程序以繼續。系統可能會提示您輸入密碼,輸入密碼,然後單擊提交。

7

在這裡您可以看到我們的應用程序已經創建。我們在左上角有我們的應用程序名稱和我們的應用程序 ID。單擊Facebook Login以便我們可以在我們的應用程序上設置 Facebook 登錄功能。

8

我將在本教程的 android 平台上工作。單擊 Android 徽標繼續。

9

在您的project-level > build.gradle文件中將代碼添加到buildscript{repositories{ }}

buildscript {
    ext.kotlin_version = '1.6.10'
    repositories {
        google()
        mavenCentral() // Add Here
    }

    dependencies {
        classpath 'com.android.tools.build:gradle:7.1.2'
        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
    }
}

allprojects {
    repositories {
        google()
        mavenCentral() // Add Here
    }
}

rootProject.buildDir = '../build'
subprojects {
    project.buildDir = "${rootProject.buildDir}/${project.name}"
}
subprojects {
    project.evaluationDependsOn(':app')
}

task clean(type: Delete) {
    delete rootProject.buildDir
}

在您的app-level>build.gradle文件中,將代碼添加到依賴項部分。

def localProperties = new Properties()
def localPropertiesFile = rootProject.file('local.properties')
if (localPropertiesFile.exists()) {
    localPropertiesFile.withReader('UTF-8') { reader ->
        localProperties.load(reader)
    }
}

def flutterRoot = localProperties.getProperty('flutter.sdk')
if (flutterRoot == null) {
    throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.")
}

def flutterVersionCode = localProperties.getProperty('flutter.versionCode')
if (flutterVersionCode == null) {
    flutterVersionCode = '1'
}

def flutterVersionName = localProperties.getProperty('flutter.versionName')
if (flutterVersionName == null) {
    flutterVersionName = '1.0'
}

apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"

android {
    compileSdkVersion flutter.compileSdkVersion
    ndkVersion flutter.ndkVersion

    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }

    kotlinOptions {
        jvmTarget = '1.8'
    }

    sourceSets {
        main.java.srcDirs += 'src/main/kotlin'
    }

    defaultConfig {
        // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
        applicationId "com.example.facebook_auth"
        // You can update the following values to match your application needs.
        // For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-build-configuration.
        minSdkVersion flutter.minSdkVersion
        targetSdkVersion flutter.targetSdkVersion
        versionCode flutterVersionCode.toInteger()
        versionName flutterVersionName
    }

    buildTypes {
        release {
            // TODO: Add your own signing config for the release build.
            // Signing with the debug keys for now, so `flutter run --release` works.
            signingConfig signingConfigs.debug
        }
    }
}

flutter {
    source '../..'
}

dependencies {
    implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
    implementation 'com.facebook.android:facebook-android-sdk:latest.release' // Add This Line Here.
}

如果您已成功完成,請單擊下一步。

十

在第 3 步中,輸入Package Name和 ,Default Activity Class Name如上所示。您可以通過轉到android>app>build.gradleFlutter 項目中的文件來獲取包名稱。

點擊保存以繼續設置應用程序。

11

在第 4 步中,我們需要生成一個開發密鑰哈希,以確保我們的應用程序與 Facebook 之間交互的真實性。我在 Windows 機器上,所以我將單擊openssl-for-windows並下載並解壓縮特定於我的 PC(32 位或 64 位)的 zip 文件。複製下面的代碼並將其粘貼到您的終端上。

keytool -exportcert -alias androiddebugkey -keystore "C:\Users\USERNAME\.android\debug.keystore" | "PATH_TO_OPENSSL_LIBRARY\bin\openssl" sha1 -binary | "PATH_TO_OPENSSL_LIBRARY\bin\openssl" base64

將 USERNAME 更改為您自己的並將路徑添加到openss\bin文件夾。就我而言,我有這個:

第十二

在這裡,我將用戶名更改為我的系統用戶並添加了openssl\bin文件夾的路徑。當提示輸入密碼時,使用android. 這將生成一個密鑰供您複製並粘貼到您網頁的“密鑰哈希”部分。

14

點擊保存並繼續。

14

第五步,啟用單點登錄,點擊保存並下一步。

15

在第 6 步中,我們將編輯資源和清單文件。在您的 上app>src>main>res>values,創建一個string.xml文件並添加以下代碼:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string name="app_name">App Name</string>
    <string name="facebook_app_id">App ID</string>
    <string name="fb_login_protocol_scheme">Login Protocol Scheme</string>
    <string name="facebook_client_token">Client Token</string>
</resources>

facebook_app_id可以在瀏覽器的上方找到,並且您fb_login_protocol_scheme是帶有前綴的應用程序 ID fb(例如,如果您的應用程序 ID 為1234,則您的協議方案將為fb1234)。要獲取您的facebook_client_token,在您的儀表板上,導航到Settings>Advanced>Security>Client Token。就我而言:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string name="app_name">Auth Tutorial</string>
    <string name="facebook_app_id">1924520271082903</string>
    <string name="fb_login_protocol_scheme">fb1924520271082903</string>
    <string name="facebook_client_token">ab808c0a71a13009bcf8792433ff6b94</string>
</resources>

最後,轉到您的AndroidManifest.xml文件並複制以下代碼:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.facebook_auth">
    
    <!-- FACEBOOK CONFIGURATIONS -->
    <uses-permission android:name="android.permission.INTERNET"/>
    <!-- FACEBOOK CONFIGURATIONS ENDS HERE -->  


    <application
        android:label="facebook_auth"
        android:name="${applicationName}"
        android:icon="@mipmap/ic_launcher">
        <activity
            android:name=".MainActivity"
            android:exported="true"
            android:launchMode="singleTop"
            android:theme="@style/LaunchTheme"
            android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
            android:hardwareAccelerated="true"
            android:windowSoftInputMode="adjustResize">
            <meta-data
              android:name="io.flutter.embedding.android.NormalTheme"
              android:resource="@style/NormalTheme"
              />
            <intent-filter>
                <action android:name="android.intent.action.MAIN"/>
                <category android:name="android.intent.category.LAUNCHER"/>
            </intent-filter>
        </activity>
        <meta-data
            android:name="flutterEmbedding"
            android:value="2" />
        
            <!-- FACEBOOK CONFIGURATIONS -->
        <meta-data android:name="com.facebook.sdk.ApplicationId" android:value="@string/facebook_app_id"/>
        <meta-data android:name="com.facebook.sdk.ClientToken" android:value="@string/facebook_client_token"/>

        <activity android:name="com.facebook.FacebookActivity"
            android:configChanges=
                "keyboard|keyboardHidden|screenLayout|screenSize|orientation"
            android:label="@string/app_name" />
        <activity
            android:name="com.facebook.CustomTabActivity"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.VIEW" />
                <category android:name="android.intent.category.DEFAULT" />
                <category android:name="android.intent.category.BROWSABLE" />
                <data android:scheme="@string/fb_login_protocol_scheme" />
            </intent-filter>
        </activity>
        <!--FACEBOOK CONFIGURATION ENDS HERE -->
    </application>
</manifest>

注意:我評論了您要復制和粘貼的行。您已完成與 Facebook 相關的所有任務。接下來,我們將開始向我們的應用程序添加功能。

添加功能

平台配置完成後,讓我們設置我們的應用程序。在我們的 main.dart 文件中,我們將向按鈕添加功能。在onPressed參數上,添加以下代碼。

Navigator.push(
                context,
                MaterialPageRoute(
                  builder: (context) => const UserScreen(),
                ),
              );

UserScreen()上面的代碼允許我們在單擊按鈕時移動到下一個屏幕( )。user_screen.dart在 lib 文件夾中創建一個名為的新 dart 文件。該文件將用於顯示從 Facebook 獲取的用戶數據。

// user.dart

import 'package:flutter/material.dart';
import 'package:flutter_facebook_auth/flutter_facebook_auth.dart';

class UserScreen extends StatefulWidget {
  const UserScreen({Key? key}) : super(key: key);

  @override
  State<UserScreen> createState() => _UserScreenState();
}

class _UserScreenState extends State<UserScreen> {
  Map<String, dynamic>? _userData;
  AccessToken? _accessToken;
  bool? _checking = true;

  _ifUserIsLoggedIn() async {
    final accessToken = await FacebookAuth.instance.accessToken;

    setState(() {
      _checking = false;
    });

    if (accessToken != null) {
      final userData = await FacebookAuth.instance.getUserData();
      _accessToken = accessToken;
      setState(() {
        _userData = userData;
      });
    } else {
      _login();
    }
  }

  _login() async {
    final LoginResult loginResult = await FacebookAuth.instance.login();

    if (loginResult.status == LoginStatus.success) {
      _accessToken = loginResult.accessToken;
      final userInfo = await FacebookAuth.instance.getUserData();
      _userData = userInfo;
    } else {
      print('ResultStatus: ${loginResult.status}');
      print('Message: ${loginResult.message}');
    }
  }

  _logOut() async {
    await FacebookAuth.instance.logOut();
    _accessToken = null;
    _userData = null;
  }

  @override
  void initState() {
    super.initState();
    _ifUserIsLoggedIn();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        body: _checking!
            ? const Center(
                child: CircularProgressIndicator(),
              )
            : Center(
                child: Column(
                  mainAxisAlignment: MainAxisAlignment.center,
                  crossAxisAlignment: CrossAxisAlignment.center,
                  children: [
                    const Text('Welcome'),
                    _userData != null
                        ? Text(
                            '${_userData!['name']}',
                            style: TextStyle(
                                fontWeight: FontWeight.bold, fontSize: 28),
                          )
                        : Container(),
                    _userData != null
                        ? Container(
                            child: Image.network(
                                _userData!\['picture'\]['data']['url']),
                          )
                        : Container(),
                    const SizedBox(
                      height: 20,
                    ),
                    ElevatedButton(
                      onPressed: () {
                        _logOut();
                        Navigator.pop(context);
                      },
                      child: const Text('Log Out'),
                    ),
                  ],
                ),
              ));
  }
}

讓我們分解上面的代碼。

Map<String, dynamic>? _userData;
  AccessToken? _accessToken;
  bool? _checking = true;

在上面的代碼中,我們有三個可為空的變量:

  • _userData: 登錄時保存用戶信息。
  • _accessToken:登錄時會自動生成訪問令牌;此變量將為我們保存該訪問令牌。
  • _checking:這將檢查用戶之前是否登錄過。
_ifUserIsLoggedIn() async {
    final accessToken = await FacebookAuth.instance.accessToken;

    setState(() {
      _checking = false;
    });

    if (accessToken != null) {
      final userData = await FacebookAuth.instance.getUserData();
      _accessToken = accessToken;
      setState(() {
        _userData = userData;
      });
    } else {
      _login();
    }
  }

  _login() async {
    final LoginResult loginResult = await FacebookAuth.instance.login();

    if (loginResult.status == LoginStatus.success) {
      _accessToken = loginResult.accessToken;
      final userInfo = await FacebookAuth.instance.getUserData();
      _userData = userInfo;
    } else {
      print('ResultStatus: ${loginResult.status}');
      print('Message: ${loginResult.message}');
    }
  }

  _logOut() async {
    await FacebookAuth.instance.logOut();
    _accessToken = null;
    _userData = null;
  }

查看上面的代碼,我們有三個異步函數:

  • _ifUserIsLoggedIn():這將檢查用戶是否已登錄並獲取訪問令牌和用戶數據。
  • _login():登錄函數讓我們登錄,如果登錄狀態為成功,它應該獲取用戶數據和生成的訪問令牌。
  • _logOut():這會將用戶數據和訪問令牌設置為 null,然後將我們帶回第一頁。
Scaffold(
        body: _checking!
            ? const Center(
                child: CircularProgressIndicator(),
              )
            : Center(
                child: Column(
                  mainAxisAlignment: MainAxisAlignment.center,
                  crossAxisAlignment: CrossAxisAlignment.center,
                  children: [
                    const Text('Welcome'),
                    _userData != null
                        ? Text(
                            '${_userData!['name']}',
                            style: TextStyle(
                                fontWeight: FontWeight.bold, fontSize: 28),
                          )
                        : Container(),
                    _userData != null
                        ? Container(
                            child: Image.network(
                                _userData!\['picture'\]['data']['url']),
                          )
                        : Container(),
                    const SizedBox(
                      height: 20,
                    ),
                    ElevatedButton(
                      onPressed: () {
                        _logOut();
                        Navigator.pop(context);
                      },
                      child: const Text('Log Out'),
                    ),
                  ],
                ),
              ));

上面的代碼在屏幕上顯示了我們的值。我們使用三元運算符,它是 dart 中簡化的 if 和 else 語句。它檢查變量的值_checking是否為真,然後顯示進度指示器;否則,顯示用戶數據。我們還有一個註銷按鈕,可以使用該_logOut功能並將我們帶回主屏幕。

測試應用程序

完成所有配置和設置後,讓我們測試我們的應用程序。使用終端中的命令在模擬器或實際設備上運行應用程序。該命令flutter run將構建應用程序並將其安裝在您的設備上。

視頻

結論

我們的應用程序需要身份驗證。沒有它,您會使數據容易受到破壞和未經授權的訪問。

鏈接:https ://blog.openreplay.com/implementing-facebook-authentication-for-flutter

#flutter #auth

如何為 Flutter 應用實現 Facebook 身份驗證
Thierry  Perret

Thierry Perret

1661149920

Implémenter L'authentification Facebook Pour L'application Flutter

L'authentification est un processus de sécurité par lequel un utilisateur doit fournir son identité pour accéder à une application, à un système particulier ou à une information ou ressource spécifique. En matière de sécurité informatique, l'authentification est le processus ou l'action de vérification de l'identité d'un utilisateur. Sans authentification, les réseaux informatiques sont ouverts aux attaques et un pirate peut vouloir accéder à des informations ou ressources confidentielles.

Flutter nous fournit un package appelé flutter_facebook_auth, où nous pouvons facilement ajouter une connexion Facebook à notre application Flutter. Il nous offre de nombreuses fonctionnalités, notamment:

  • Connectez-vous sur IOS, Android et Web
  • Connexion express sur Android
  • Fournissez un jeton d'accès pour faire une demande à l'API Graph et bien plus encore.

Pour la documentation complète, rendez-vous sur cette page .

Dans cet article, nous allons configurer une application pour montrer comment utiliser ce package dans notre application Flutter.

Création de notre application Flutter

Pour commencer, rendez-vous sur GitHub et clonez les fichiers de démarrage créés pour ce projet. Ouvrez le pubspec.yamlfichier et ajoutez flutter_facebook_auth-le sous cupertino_iconsou exécutez- flutter pub add flutter_facebook_authle sur votre terminal.

name: facebook_auth
description: A new Flutter project.

publish_to: `none 

version: 1.0.0+1

environment:
  sdk: ">=2.17.6 <3.0.0"

dependencies:
  flutter:
    sdk: flutter

  cupertino_icons: ^1.0.2
  flutter_facebook_auth: ^4.4.0+1 # Add This Line

dev_dependencies:
  flutter_test:
    sdk: flutter

  flutter_lints: ^2.0.0

flutter:
  uses-material-design: true

Ajouter des dépendances à notre application

Avant d'ajouter des fonctionnalités à notre application, nous devons configurer les fichiers racine du projet pour nous accorder l'accès à Facebook Login. Sur votre navigateur, rendez-vous sur Facebook Developer pour créer un compte Facebook Developer et commencer à créer notre application.

première

Cliquez sur le bouton de connexion. Cela vous demandera de vous connecter en utilisant vos informations Facebook.

2

Entrez vos informations de connexion et appuyez sur le bouton Connexion pour continuer.

3

Cliquez sur My Apps, et nous pourrons commencer à créer notre application sur Facebook.

4

Ici, aucune application n'a été créée. Appuyez sur le bouton Créer une application pour que nous puissions commencer à créer notre application

5

Ici, nous pouvons choisir n'importe quel type d'application. Je vais choisir Business pour ce tutoriel et cliquer sur Suivant.

6

Ajoutez un nom d'affichage de votre choix et cliquez sur créer une application pour continuer. Vous serez peut-être invité à entrer votre mot de passe, entrez votre mot de passe et cliquez sur Soumettre.

sept

Ici, vous pouvez voir que notre application a été créée. Nous avons notre nom d'application en haut à gauche et notre identifiant d'application. Cliquez sur Facebook Loginpour que nous puissions configurer la fonction de connexion Facebook sur notre application.

8

Je vais travailler sur la plate-forme Android pour ce tutoriel. Cliquez sur le logo Android pour continuer.

9

Dans votre project-level > build.gradlefichier, ajoutez le code aubuildscript{repositories{ }}

buildscript {
    ext.kotlin_version = '1.6.10'
    repositories {
        google()
        mavenCentral() // Add Here
    }

    dependencies {
        classpath 'com.android.tools.build:gradle:7.1.2'
        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
    }
}

allprojects {
    repositories {
        google()
        mavenCentral() // Add Here
    }
}

rootProject.buildDir = '../build'
subprojects {
    project.buildDir = "${rootProject.buildDir}/${project.name}"
}
subprojects {
    project.evaluationDependsOn(':app')
}

task clean(type: Delete) {
    delete rootProject.buildDir
}

Et dans votre app-level>build.gradlefichier, ajoutez le code à la section des dépendances.

def localProperties = new Properties()
def localPropertiesFile = rootProject.file('local.properties')
if (localPropertiesFile.exists()) {
    localPropertiesFile.withReader('UTF-8') { reader ->
        localProperties.load(reader)
    }
}

def flutterRoot = localProperties.getProperty('flutter.sdk')
if (flutterRoot == null) {
    throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.")
}

def flutterVersionCode = localProperties.getProperty('flutter.versionCode')
if (flutterVersionCode == null) {
    flutterVersionCode = '1'
}

def flutterVersionName = localProperties.getProperty('flutter.versionName')
if (flutterVersionName == null) {
    flutterVersionName = '1.0'
}

apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"

android {
    compileSdkVersion flutter.compileSdkVersion
    ndkVersion flutter.ndkVersion

    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }

    kotlinOptions {
        jvmTarget = '1.8'
    }

    sourceSets {
        main.java.srcDirs += 'src/main/kotlin'
    }

    defaultConfig {
        // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
        applicationId "com.example.facebook_auth"
        // You can update the following values to match your application needs.
        // For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-build-configuration.
        minSdkVersion flutter.minSdkVersion
        targetSdkVersion flutter.targetSdkVersion
        versionCode flutterVersionCode.toInteger()
        versionName flutterVersionName
    }

    buildTypes {
        release {
            // TODO: Add your own signing config for the release build.
            // Signing with the debug keys for now, so `flutter run --release` works.
            signingConfig signingConfigs.debug
        }
    }
}

flutter {
    source '../..'
}

dependencies {
    implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
    implementation 'com.facebook.android:facebook-android-sdk:latest.release' // Add This Line Here.
}

Cliquez sur Suivant si vous l'avez fait avec succès.

Dix

À l'étape 3, saisissez le Package Nameet le Default Activity Class Namecomme indiqué ci-dessus. Vous pouvez obtenir le nom de votre package en accédant à votre android>app>build.gradlefichier dans votre projet Flutter.

Appuyez sur Enregistrer pour continuer à configurer l'application.

11

À l'étape 4, nous devons générer un hachage de clé de développement pour garantir l'authenticité de l'interaction entre notre application et Facebook. Je suis sur une machine windows, je vais donc cliquer sur le openssl-for-windowset télécharger et extraire le fichier zip spécifique à mon PC (32bit ou 64bit). Copiez le code ci-dessous et collez-le sur votre terminal.

keytool -exportcert -alias androiddebugkey -keystore "C:\Users\USERNAME\.android\debug.keystore" | "PATH_TO_OPENSSL_LIBRARY\bin\openssl" sha1 -binary | "PATH_TO_OPENSSL_LIBRARY\bin\openssl" base64

Remplacez le USERNAME par le vôtre et ajoutez le chemin d'accès au openss\bindossier. Dans mon cas, j'ai ceci :

douzième

Ici, j'ai changé le nom d'utilisateur en mon utilisateur système et ajouté le chemin d'accès au openssl\bindossier. Lorsque vous êtes invité à saisir un mot de passe, utilisez android. Cela générera une clé que vous pourrez copier et coller dans la section Key Hashes de votre page Web.

14

Appuyez sur Enregistrer et continuer.

14

Étape 5, activez l'authentification unique, cliquez sur Enregistrer et Suivant.

15

À l'étape 6, nous allons modifier le fichier Resources and Manifest. Sur votre app>src>main>res>values, créez un string.xmlfichier et ajoutez le code ci-dessous :

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string name="app_name">App Name</string>
    <string name="facebook_app_id">App ID</string>
    <string name="fb_login_protocol_scheme">Login Protocol Scheme</string>
    <string name="facebook_client_token">Client Token</string>
</resources>

Votre facebook_app_idpeut être trouvé ci-dessus dans votre navigateur, et votre fb_login_protocol_schemeest votre identifiant d'application avec un préfixe fb(par exemple, si votre identifiant d'application est 1234, votre schéma de protocole sera fb1234). Pour obtenir votre facebook_client_token, Sur votre tableau de bord, accédez à Settings>Advanced>Security>Client Token. Dans mon cas:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string name="app_name">Auth Tutorial</string>
    <string name="facebook_app_id">1924520271082903</string>
    <string name="fb_login_protocol_scheme">fb1924520271082903</string>
    <string name="facebook_client_token">ab808c0a71a13009bcf8792433ff6b94</string>
</resources>

Enfin, allez dans votre AndroidManifest.xmlfichier et copiez le code ci-dessous :

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.facebook_auth">
    
    <!-- FACEBOOK CONFIGURATIONS -->
    <uses-permission android:name="android.permission.INTERNET"/>
    <!-- FACEBOOK CONFIGURATIONS ENDS HERE -->  


    <application
        android:label="facebook_auth"
        android:name="${applicationName}"
        android:icon="@mipmap/ic_launcher">
        <activity
            android:name=".MainActivity"
            android:exported="true"
            android:launchMode="singleTop"
            android:theme="@style/LaunchTheme"
            android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
            android:hardwareAccelerated="true"
            android:windowSoftInputMode="adjustResize">
            <meta-data
              android:name="io.flutter.embedding.android.NormalTheme"
              android:resource="@style/NormalTheme"
              />
            <intent-filter>
                <action android:name="android.intent.action.MAIN"/>
                <category android:name="android.intent.category.LAUNCHER"/>
            </intent-filter>
        </activity>
        <meta-data
            android:name="flutterEmbedding"
            android:value="2" />
        
            <!-- FACEBOOK CONFIGURATIONS -->
        <meta-data android:name="com.facebook.sdk.ApplicationId" android:value="@string/facebook_app_id"/>
        <meta-data android:name="com.facebook.sdk.ClientToken" android:value="@string/facebook_client_token"/>

        <activity android:name="com.facebook.FacebookActivity"
            android:configChanges=
                "keyboard|keyboardHidden|screenLayout|screenSize|orientation"
            android:label="@string/app_name" />
        <activity
            android:name="com.facebook.CustomTabActivity"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.VIEW" />
                <category android:name="android.intent.category.DEFAULT" />
                <category android:name="android.intent.category.BROWSABLE" />
                <data android:scheme="@string/fb_login_protocol_scheme" />
            </intent-filter>
        </activity>
        <!--FACEBOOK CONFIGURATION ENDS HERE -->
    </application>
</manifest>

Remarque : J'ai commenté les lignes que vous êtes censé copier et coller. Vous avez terminé toutes les tâches relatives à Facebook. Ensuite, nous commencerons à ajouter des fonctionnalités à notre application.

Ajout des fonctionnalités

Une fois les configurations de la plate-forme terminées, configurons notre application. Dans notre fichier main.dart, nous allons ajouter des fonctionnalités à notre bouton. Sur le onPressedparamètre, ajoutez le code ci-dessous.

Navigator.push(
                context,
                MaterialPageRoute(
                  builder: (context) => const UserScreen(),
                ),
              );

Le code ci-dessus nous permet de passer à l'écran suivant (le UserScreen()) lorsque le bouton est cliqué. Créez un nouveau fichier Dart nommé user_screen.dartdans le dossier lib. Ce fichier sera utilisé pour afficher les données utilisateur obtenues de Facebook.

// user.dart

import 'package:flutter/material.dart';
import 'package:flutter_facebook_auth/flutter_facebook_auth.dart';

class UserScreen extends StatefulWidget {
  const UserScreen({Key? key}) : super(key: key);

  @override
  State<UserScreen> createState() => _UserScreenState();
}

class _UserScreenState extends State<UserScreen> {
  Map<String, dynamic>? _userData;
  AccessToken? _accessToken;
  bool? _checking = true;

  _ifUserIsLoggedIn() async {
    final accessToken = await FacebookAuth.instance.accessToken;

    setState(() {
      _checking = false;
    });

    if (accessToken != null) {
      final userData = await FacebookAuth.instance.getUserData();
      _accessToken = accessToken;
      setState(() {
        _userData = userData;
      });
    } else {
      _login();
    }
  }

  _login() async {
    final LoginResult loginResult = await FacebookAuth.instance.login();

    if (loginResult.status == LoginStatus.success) {
      _accessToken = loginResult.accessToken;
      final userInfo = await FacebookAuth.instance.getUserData();
      _userData = userInfo;
    } else {
      print('ResultStatus: ${loginResult.status}');
      print('Message: ${loginResult.message}');
    }
  }

  _logOut() async {
    await FacebookAuth.instance.logOut();
    _accessToken = null;
    _userData = null;
  }

  @override
  void initState() {
    super.initState();
    _ifUserIsLoggedIn();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        body: _checking!
            ? const Center(
                child: CircularProgressIndicator(),
              )
            : Center(
                child: Column(
                  mainAxisAlignment: MainAxisAlignment.center,
                  crossAxisAlignment: CrossAxisAlignment.center,
                  children: [
                    const Text('Welcome'),
                    _userData != null
                        ? Text(
                            '${_userData!['name']}',
                            style: TextStyle(
                                fontWeight: FontWeight.bold, fontSize: 28),
                          )
                        : Container(),
                    _userData != null
                        ? Container(
                            child: Image.network(
                                _userData!\['picture'\]['data']['url']),
                          )
                        : Container(),
                    const SizedBox(
                      height: 20,
                    ),
                    ElevatedButton(
                      onPressed: () {
                        _logOut();
                        Navigator.pop(context);
                      },
                      child: const Text('Log Out'),
                    ),
                  ],
                ),
              ));
  }
}

Décomposons le code ci-dessus.

Map<String, dynamic>? _userData;
  AccessToken? _accessToken;
  bool? _checking = true;

Dans le code ci-dessus, nous avons trois variables nullables :

  • _userData: Cela contient les informations de l'utilisateur lorsqu'il est connecté.
  • _accessToken: Une fois connecté, un jeton d'accès sera généré automatiquement ; cette variable contiendra ce jeton d'accès pour nous.
  • _checking: Cela vérifie si l'utilisateur est connecté avant ou non.
_ifUserIsLoggedIn() async {
    final accessToken = await FacebookAuth.instance.accessToken;

    setState(() {
      _checking = false;
    });

    if (accessToken != null) {
      final userData = await FacebookAuth.instance.getUserData();
      _accessToken = accessToken;
      setState(() {
        _userData = userData;
      });
    } else {
      _login();
    }
  }

  _login() async {
    final LoginResult loginResult = await FacebookAuth.instance.login();

    if (loginResult.status == LoginStatus.success) {
      _accessToken = loginResult.accessToken;
      final userInfo = await FacebookAuth.instance.getUserData();
      _userData = userInfo;
    } else {
      print('ResultStatus: ${loginResult.status}');
      print('Message: ${loginResult.message}');
    }
  }

  _logOut() async {
    await FacebookAuth.instance.logOut();
    _accessToken = null;
    _userData = null;
  }

En regardant le code ci-dessus, nous avons trois fonctions asynchrones :

  • _ifUserIsLoggedIn(): Cela vérifie si l'utilisateur est connecté et obtient le jeton d'accès et les données de l'utilisateur.
  • _login(): La fonction de connexion nous permet de nous connecter, et si l'état de connexion a réussi, elle devrait obtenir les données de l'utilisateur et le jeton d'accès généré.
  • _logOut(): Cela définit les données utilisateur et le jeton d'accès sur null, puis nous ramène à la première page.
Scaffold(
        body: _checking!
            ? const Center(
                child: CircularProgressIndicator(),
              )
            : Center(
                child: Column(
                  mainAxisAlignment: MainAxisAlignment.center,
                  crossAxisAlignment: CrossAxisAlignment.center,
                  children: [
                    const Text('Welcome'),
                    _userData != null
                        ? Text(
                            '${_userData!['name']}',
                            style: TextStyle(
                                fontWeight: FontWeight.bold, fontSize: 28),
                          )
                        : Container(),
                    _userData != null
                        ? Container(
                            child: Image.network(
                                _userData!\['picture'\]['data']['url']),
                          )
                        : Container(),
                    const SizedBox(
                      height: 20,
                    ),
                    ElevatedButton(
                      onPressed: () {
                        _logOut();
                        Navigator.pop(context);
                      },
                      child: const Text('Log Out'),
                    ),
                  ],
                ),
              ));

Le code ci-dessus affiche nos valeurs à l'écran. Nous utilisons un opérateur ternaire, qui est une instruction if et else simplifiée dans dart. Il vérifie si la valeur de la variable _checkingest vraie, puis affiche un indicateur de progression ; sinon, afficher les données de l'utilisateur. Nous avons également un bouton de déconnexion qui reprend la _logOutfonction et nous ramène à l'écran d'accueil.

Tester l'application

Une fois la configuration et l'installation terminées, testons notre application. Exécutez l'application sur un émulateur ou un appareil réel à l'aide de la commande dans un terminal. La commande flutter runcréera l'application et l'installera sur votre appareil.

vidéo

Conclusion

L'authentification est nécessaire pour notre application. Sans cela, vous gardez les données vulnérables aux violations et aux accès non autorisés.

Lien : https://blog.openreplay.com/implementing-facebook-authentication-for-flutter

#flutter #auth

Implémenter L'authentification Facebook Pour L'application Flutter
Hans  Marvin

Hans Marvin

1661142584

How to Implement Facebook Authentication for Flutter App

Authentication is a security process whereby a user has to provide their identity to access a particular application, system, or a piece of specific information or resource. In terms of computer security, authentication is the process or action of verifying the identity of a user. Without authentication, computer networks are open to attacks, and a hacker might want to gain access to confidential information or resources.

Flutter provides us with a package known as flutter_facebook_auth, where we can easily add a Facebook login to our Flutter application. It provides us with a lot of features which include:

  • Login on IOS, Android, and Web
  • Express login on Android
  • Provide an access token to make a request to the Graph API and a lot more.

For the complete documentation, head to this page.

In this article, we will set up an app to show how to use this package in our Flutter application.

See more at: https://blog.openreplay.com/implementing-facebook-authentication-for-flutter

#flutter #auth

How to Implement Facebook Authentication for Flutter App

Simple Firebase Authentication for All Next.js Rendering Strategies

next-firebase-auth

Simple Firebase authentication for all Next.js rendering strategies.

What It Does

This package makes it simple to get the authenticated Firebase user and ID token during both client-side and server-side rendering (SSR).

     🌍   Support for all Next.js rendering strategies

     🔒   Signed, secure, HTTP-only cookies by default

     🆔   Server-side access to the user's Firebase ID token

     🍪   Built-in cookie management

     ↩️   Built-in support for redirecting based on the user's auth status

We treat the Firebase JS SDK as the source of truth for auth status. When the user signs in, we call an endpoint to generate a refresh token and store the user info, ID token, and refresh token in cookies. Future requests to SSR pages receive the user info and ID token from cookies, refreshing the ID token as needed. When the user logs out, we unset the cookies.

Demo

See a live demo of the example app.

When (Not) to Use this Package

Depending on your app's needs, other approaches might work better for you.

If your app only uses static pages or doesn't need the Firebase user for SSR, use the Firebase JS SDK directly to load the user on the client side.

  • Pros: It's simpler and removes this package as a dependency.
  • Cons: You will not have access to the Firebase user when you use getServerSideProps.

If your app needs the Firebase user for SSR (but does not need the ID token server side), you could consider one of these approaches:

  1. On the client, set a JavaScript cookie with the Firebase user information once the Firebase JS SDK loads.
    • Pros: You won't need login/logout API endpoints. You can structure the authed user data however you'd like.
    • Cons: The cookie will be unsigned and accessible to other JavaScript, making this approach less secure. You won't always have access to the Firebase ID token server side, so you won't be able to access other Firebase services. (Note that you can set the ID token in the cookie, but it will expire after an hour and be invalid for future server-side-rendered pages.)
  2. Use Firebase's session cookies.
    • Pros: It removes this package as a dependency.
    • Cons: You won't have access to the Firebase ID token server side, so you won't be able to access other Firebase services. You'll need to implement the logic for verifying the session and managing the session state.

If your app needs a generalized authentication solution—not specifically Firebase authentication—you could consider using NextAuth.js. NextAuth.js does not use Firebase authentication but supports a wide variety of identity providers, including Google. Read more here about the differences between next-firebase-auth and NextAuth.js to see which works best for your needs.

This package will likely be helpful if you expect to use both static pages and SSR or if you need access to Firebase ID tokens server side.

A quick note on what this package does not do:

  • It does not provide authentication UI. Consider firebaseui-web or build your own.
  • It does not extend Firebase functionality beyond providing universal access to the authed user. Use the Firebase admin SDK and Firebase JS SDK for any other needs.

Get Started

Install:

Firebase v8: yarn add next-firebase-auth or npm i next-firebase-auth

Firebase v9+: yarn add next-firebase-auth@canary or npm i next-firebase-auth@canary

⚠️ If you're using v9 of the Firebase JS SDK, use next-firebase-auth@canary. This is an unstable v1 prerelease. Track progress on v1 in this issue.

Make sure peer dependencies are also installed:

yarn add firebase firebase-admin next react react-dom

Create a module to initialize next-firebase-auth.

Example config:

See config documentation for details

// ./initAuth.js
import { init } from 'next-firebase-auth'

const initAuth = () => {
  init({
    authPageURL: '/auth',
    appPageURL: '/',
    loginAPIEndpoint: '/api/login', // required
    logoutAPIEndpoint: '/api/logout', // required
    onLoginRequestError: (err) => {
      console.error(err)
    },
    onLogoutRequestError: (err) => {
      console.error(err)
    },
    firebaseAuthEmulatorHost: 'localhost:9099',
    firebaseAdminInitConfig: {
      credential: {
        projectId: 'my-example-app-id',
        clientEmail: 'example-abc123@my-example-app.iam.gserviceaccount.com',
        // The private key must not be accessible on the client side.
        privateKey: process.env.FIREBASE_PRIVATE_KEY,
      },
      databaseURL: 'https://my-example-app.firebaseio.com',
    },
    // Use application default credentials (takes precedence over firebaseAdminInitConfig if set)
    // useFirebaseAdminDefaultCredential: true,
    firebaseClientInitConfig: {
      apiKey: 'MyExampleAppAPIKey123', // required
      authDomain: 'my-example-app.firebaseapp.com',
      databaseURL: 'https://my-example-app.firebaseio.com',
      projectId: 'my-example-app-id',
    },
    cookies: {
      name: 'ExampleApp', // required
      // Keys are required unless you set `signed` to `false`.
      // The keys cannot be accessible on the client side.
      keys: [
        process.env.COOKIE_SECRET_CURRENT,
        process.env.COOKIE_SECRET_PREVIOUS,
      ],
      httpOnly: true,
      maxAge: 12 * 60 * 60 * 24 * 1000, // twelve days
      overwrite: true,
      path: '/',
      sameSite: 'strict',
      secure: true, // set this to false in local (non-HTTPS) development
      signed: true,
    },
    onVerifyTokenError: (err) => {
      console.error(err)
    },
    onTokenRefreshError: (err) => {
      console.error(err)
    },
  })
}

export default initAuth

Set the private environment variables FIREBASE_PRIVATE_KEY, COOKIE_SECRET_CURRENT, and COOKIE_SECRET_PREVIOUS in .env.local. If you have enabled the Firebase Authentication Emulator, you will also need to set the FIREBASE_AUTH_EMULATOR_HOST environment variable.

Initialize next-firebase-auth in _app.js:

// ./pages/_app.js
import initAuth from '../initAuth' // the module you created above

initAuth()

function MyApp({ Component, pageProps }) {
  return <Component {...pageProps} />
}

export default MyApp

Create login and logout API endpoints that set auth cookies:

// ./pages/api/login
import { setAuthCookies } from 'next-firebase-auth'
import initAuth from '../../initAuth' // the module you created above

initAuth()

const handler = async (req, res) => {
  try {
    await setAuthCookies(req, res)
  } catch (e) {
    return res.status(500).json({ error: 'Unexpected error.' })
  }
  return res.status(200).json({ success: true })
}

export default handler
// ./pages/api/logout
import { unsetAuthCookies } from 'next-firebase-auth'
import initAuth from '../../initAuth' // the module you created above

initAuth()

const handler = async (req, res) => {
  try {
    await unsetAuthCookies(req, res)
  } catch (e) {
    return res.status(500).json({ error: 'Unexpected error.' })
  }
  return res.status(200).json({ success: true })
}

export default handler

Finally, use the authenticated user in a page:

// ./pages/demo
import React from 'react'
import {
  useAuthUser,
  withAuthUser,
  withAuthUserTokenSSR,
} from 'next-firebase-auth'

const Demo = () => {
  const AuthUser = useAuthUser()
  return (
    <div>
      <p>Your email is {AuthUser.email ? AuthUser.email : 'unknown'}.</p>
    </div>
  )
}

// Note that this is a higher-order function.
export const getServerSideProps = withAuthUserTokenSSR()()

export default withAuthUser()(Demo)

API


init(config)

Initializes next-firebase-auth, taking a config object. Must be called before calling any other method.

withAuthUser({ ...options })(PageComponent)

A higher-order function to provide the AuthUser context to a component. Use this with any Next.js page that will access the authed user via the useAuthUser hook. Optionally, it can client-side redirect based on the user's auth status.

It accepts the following options:

OptionDescriptionDefault
whenAuthedThe action to take if the user is authenticated. One of AuthAction.RENDER or AuthAction.REDIRECT_TO_APP.AuthAction.RENDER
whenAuthedBeforeRedirectThe action to take while waiting for the browser to redirect. Relevant when the user is authenticated and whenAuthed is set to AuthAction.REDIRECT_TO_APP. One of: AuthAction.RENDER or AuthAction.SHOW_LOADER or AuthAction.RETURN_NULL.AuthAction.RETURN_NULL
whenUnauthedBeforeInitThe action to take if the user is not authenticated but the Firebase client JS SDK has not yet initialized. One of: AuthAction.RENDER, AuthAction.REDIRECT_TO_LOGIN, AuthAction.SHOW_LOADER.AuthAction.RENDER
whenUnauthedAfterInitThe action to take if the user is not authenticated and the Firebase client JS SDK has already initialized. One of: AuthAction.RENDER, AuthAction.REDIRECT_TO_LOGIN.AuthAction.RENDER
appPageURLThe redirect destination URL when we should redirect to the app. A PageURL.config.appPageURL
authPageURLThe redirect destination URL when we should redirect to the login page. A PageURL.config.authPageURL
LoaderComponentThe component to render when the user is unauthed and whenUnauthedBeforeInit is set to AuthAction.SHOW_LOADER.null

For example, this page will redirect to the login page if the user is not authenticated:

import { withAuthUser, AuthAction } from 'next-firebase-auth'

const DemoPage = () => <div>My demo page</div>

export default withAuthUser({
  whenUnauthedAfterInit: AuthAction.REDIRECT_TO_LOGIN,
  authPageURL: '/my-login-page/',
})(DemoPage)

Here's an example of a login page that shows a loader until Firebase is initialized, then redirects to the app if the user is already logged in:

import { withAuthUser, AuthAction } from 'next-firebase-auth'

const MyLoader = () => <div>Loading...</div>

const LoginPage = () => <div>My login page</div>

export default withAuthUser({
  whenAuthed: AuthAction.REDIRECT_TO_APP,
  whenUnauthedBeforeInit: AuthAction.SHOW_LOADER,
  whenUnauthedAfterInit: AuthAction.RENDER,
  LoaderComponent: MyLoader,
})(LoginPage)

For TypeScript usage, take a look here.

withAuthUserTokenSSR({ ...options })(getServerSidePropsFunc = ({ AuthUser }) => {})

A higher-order function that wraps a Next.js pages's getServerSideProps function to provide the AuthUser context during server-side rendering. Optionally, it can server-side redirect based on the user's auth status. A wrapped function is optional; if provided, it will be called with a context object that contains an AuthUser property.

It accepts the following options:

OptionDescriptionDefault
whenAuthedThe action to take if the user is authenticated. Either AuthAction.RENDER or AuthAction.REDIRECT_TO_APP.AuthAction.RENDER
whenUnauthedThe action to take if the user is not authenticated. Either AuthAction.RENDER or AuthAction.REDIRECT_TO_LOGIN.AuthAction.RENDER
appPageURLThe redirect destination URL when we should redirect to the app. A PageURL.config.appPageURL
authPageURLThe redirect destination URL when we should redirect to the login page. A PageURL.config.authPageURL

For example, this page will SSR for authenticated users, fetching props using their Firebase ID token, and will server-side redirect to the login page if the user is not authenticated:

import { withAuthUser, AuthAction } from 'next-firebase-auth'

const DemoPage = ({ thing }) => <div>The thing is: {thing}</div>

export const getServerSideProps = withAuthUserTokenSSR({
  whenUnauthed: AuthAction.REDIRECT_TO_LOGIN,
})(async ({ AuthUser }) => {
  // Optionally, get other props.
  const token = await AuthUser.getIdToken()
  const response = await fetch('/api/my-endpoint', {
    method: 'GET',
    headers: {
      Authorization: token,
    },
  })
  const data = await response.json()
  return {
    props: {
      thing: data.thing,
    },
  }
})

export default withAuthUser()(DemoPage)

withAuthUserSSR({ ...options })(getServerSidePropsFunc = ({ AuthUser }) => {})

Behaves nearly identically to withAuthUserTokenSSR, with one key difference: it does not validate an ID token. Instead, it simply uses the AuthUser data from a cookie. Consequently:

  • It does not provide an ID token on the server side. The AuthUser provided via context will resolve to null when you call AuthUser.getIdToken().
  • It does not need to make a network request to refresh an expired ID token, so it will, on average, be faster than withAuthUserTokenSSR.
  • It does not check for token revocation. If you need verification that the user's credentials haven't been revoked, you should always use withAuthUserTokenSSR.

⚠️ Do not use this when cookies.signed is set to false. Doing so is a potential security risk, because the authed user cookie values could be modified by the client.

This takes the same options as withAuthUserTokenSSR.

useAuthUser()

A hook that returns the current AuthUser. To use this, the Next.js page must be wrapped in withAuthUser. If the user is not authenticated, useAuthUser will return an AuthUser instance with a null id.

For example:

import { useAuthUser, withAuthUser } from 'next-firebase-auth'

const Demo = () => {
  const AuthUser = useAuthUser()
  return (
    <div>
      <p>Your email is {AuthUser.email ? AuthUser.email : 'unknown'}.</p>
    </div>
  )
}

export default withAuthUser()(Demo)

setAuthCookies(req, res)

Sets cookies to store the authenticated user's info. Call this from your "login" API endpoint.

Cookies are managed with cookies. See the config for cookie options.

The req argument should be an IncomingMessage / Next.js request object. The res argument should be a ServerResponse / Next.js response object. It requires that the Authorization request header be set to the Firebase user ID token, which this package handles automatically.

This can only be called on the server side.

unsetAuthCookies(req, res)

Unsets (expires) the auth cookies. Call this from your "logout" API endpoint.

The req argument should be an IncomingMessage / Next.js request object. The res argument should be a ServerResponse / Next.js response object.

This can only be called on the server side.

verifyIdToken(token) => Promise<AuthUser>

Verifies a Firebase ID token and resolves to an AuthUser instance. This serves a similar purpose as Firebase admin SDK's verifyIdToken.

AuthAction

An object that defines rendering/redirecting options for withAuthUser and withAuthUserTokenSSR. See AuthAction.

getFirebaseAdmin() => FirebaseAdmin

Added in v0.13.1

A convenience function that returns the configured Firebase admin module.

This can only be called from the server side. It will throw an error if called from the client side.

For example:

import { getFirebaseAdmin } from 'next-firebase-auth'
// ...other imports

const Artist = ({ artists }) => {
  return (
    <ul>
      {artists.map((artist) => (
        <li>{artist.name}</li>
      ))}
    </ul>
  )
}

export async function getServerSideProps({ params: { id } }) {
  const db = getFirebaseAdmin().firestore()
  const doc = await db.collection('artists').get()
  return {
    props: {
      artists: artists.docs.map((a) => {
        return { ...a.data(), key: a.id }
      }),
    },
  }
}

export default withAuthUser()(Artist)

Config

See an example config here. Provide the config when you call init.

authPageURL

String|Function|Object – a PageURL

The default URL to navigate to when withAuthUser or withAuthUserTokenSSR need to redirect to login. Optional unless using the AuthAction.REDIRECT_TO_LOGIN auth action.

appPageURL

String|Function|Object – a PageURL

The default URL to navigate to when withAuthUser or withAuthUserTokenSSR need to redirect to the app. Optional unless using the AuthAction.REDIRECT_TO_APP auth action.

loginAPIEndpoint

String

The API endpoint this module will call when the auth state changes for an authenticated Firebase user.

Required unless a custom tokenChangedHandler is set, in which case it cannot be defined.

logoutAPIEndpoint

String

The API endpoint this module will call when the auth state changes for an unauthenticated Firebase user.

Required unless a custom tokenChangedHandler is set, in which case it cannot be defined.

onLoginRequestError

Added in v0.14.0

Function (optional)

A handler called if the login API endpoint returns a non-200 response. If a handler is not defined, this library will throw on any non-200 responses.

Not used or allowed if a custom tokenChangedHandler is set.

onLogoutRequestError

Added in v0.14.0

Function (optional)

A handler called if the logout API endpoint returns a non-200 response. If a handler is not defined, this library will throw on any non-200 responses.

Not used or allowed if a custom tokenChangedHandler is set.

tokenChangedHandler

Function

A callback that runs when the auth state changes for a particular user. Use this if you want to customize how your client-side app calls your login/logout API endpoints (for example, to use a custom fetcher or add custom headers). tokenChangedHandler receives an AuthUser as an argument and is called when the user's ID token changes, similarly to Firebase's onIdTokenChanged event.

If this callback is specified, user is responsible for:

  1. Calling their login/logout endpoints depending on the user's auth state.
  2. Passing the user's ID token in the Authorization header
  3. Ensuring it allows the request to set cookies.

See the default handler for guidance.

firebaseAuthEmulatorHost

String

The host and port for the local Firebase Auth Emulator. If this value is set, the auth emulator will be initialized with the provided host and port.

Must match the value of the FIREBASE_AUTH_EMULATOR_HOST environment variable, e.g., localhost:9099.

firebaseAdminInitConfig

Object

Configuration passed to firebase-admin's initializeApp. It should contain a credential property (a plain object) and a databaseURL property. Required unless you initialize firebase-admin yourself before initializing next-firebase-auth.

The firebaseAdminInitConfig.credential.privateKey cannot be defined on the client side and should live in a secret environment variable.

ℹ️ Using Vercel? See adding a private key to Vercel for guidance.

useFirebaseAdminDefaultCredential

Boolean

When true, firebase-admin will implicitly find your hosting environment service account during initializeApp. This is applicable for both Firebase, and Google Cloud Platform, and recommended over adding service account key to the code via file path or direct value.

Note: To setup firebase-admin, either firebaseAdminInitConfig or useFirebaseAdminDefaultCredential must be provided. Using the default credentials will override values passed to firebaseAdminInitConfig.credential if both are presented.

firebaseClientInitConfig

Object

Configuration passed to the Firebase JS SDK's initializeApp. The firebaseClientInitConfig.apiKey value is always required. Other properties are required unless you initialize the firebase app yourself before initializing next-firebase-auth.

cookies

Object

Settings used for auth cookies. We use cookies to manage cookies.

Properties include:

  • name: Used as a base for cookie names: if name is set to "MyExample", cookies will be named MyExample.AuthUser and MyExample.AuthUserTokens (plus MyExample.AuthUser.sig and MyExample.AuthUserTokens.sig if cookies are signed). Required.
  • keys: An array of strings that will be used to sign cookies; for instance, ['xD$WVv3qrP3ywY', '2x6#msoUeNhVHr']. As these strings are secrets, provide them via secret environment variables, such as [ process.env.COOKIE_SECRET_CURRENT, process.env.COOKIE_SECRET_PREVIOUS ]. The keys array is passed to the Keygrip constructor as described in the cookies package. Required unless signed is set to false.
  • All options for cookies.set.

The keys value cannot be defined on the client side and should live in a secret environment variable.

For security, the maxAge value must be two weeks or less. Note that maxAge is defined in milliseconds.

Note: The cookies' expirations will be extended automatically when the user loads the Firebase JS SDK.

The Firebase JS SDK is the source of truth for authentication, so if the cookies expire but the user is still authed with Firebase, the cookies will be automatically set again when the user loads the Firebase JS SDK—but the user will not be authed during SSR on that first request.

onVerifyTokenError

Added in v0.14.0

Function (optional)

Error handler that will be called if there's an unexpected error while verifying the user's ID token server side. It will receive a Firebase auth error.

This library will not throw when it cannot verify an ID token. Instead, it will provide an unauthenticated user to the app. It will typically handle common auth-related errors such as auth/id-token-expired and auth/user-disabled without throwing. See #366 and #174 for additional background.

onTokenRefreshError

Added in v0.14.0

Function (optional)

Error handler that will be called if there's an unexpected error while refreshing the user's ID token server side.

This library will not throw when it cannot refresh an ID token. Instead, it will provide an unauthenticated user to the app. See #366 and #174 for additional background.

Types

AuthAction

Defines actions to take depending on a user's auth status, using the following constants:

AuthAction.RENDER: render the child component

AuthAction.SHOW_LOADER: show a loader component

AuthAction.RETURN_NULL: return null instead of any component

AuthAction.REDIRECT_TO_LOGIN: redirect to the login page

AuthAction.REDIRECT_TO_APP: redirect to the app

AuthUser

The auth user object is used across server-side and client-side contexts. This is a normalized representation of a Firebase user.

id - String|null

The Firebase user's ID, or null if the user is not authenticated.

email - String|null

The Firebase user's email address, or null if the user has no email address.

emailVerified - Boolean

Whether the user's email address is verified.

phoneNumber - String|null

Added in v0.13.1

The Firebase user's phone number, or null if the user has no phone number.

displayName - String|null

Added in v0.13.1

The Firebase user's display name, or null if the user has no display name.

photoURL - String|null

Added in v0.13.1

The Firebase user's photo URL, or null if the user has no photo URL.

claims - Object

Added in v0.13.0

Any custom Firebase claims.

getIdToken - Function => Promise<String|null>

An async function that resolves to a valid Firebase ID token string, or null if no valid token is available.

clientInitialized - Boolean

Whether the Firebase JS SDK has initialized. If true, we are no longer using any user info from server-side props.

firebaseUser - FirebaseUser|null

The user from the Firebase JS SDK, if it has been initialized. Otherwise, null.

signOut - Function => Promise<void>

A method that calls Firebase's signOut if the Firebase JS SDK has been initialized. If the SDK has not been initialized, this method is a no-op.

PageURL

String|Function|Object

Used in appPageURL and authPageURL in the config and higher-order components, the PageURL defines a redirect destination URL or path.

It can be a string: /my-url/here/

Or an object:

{
  destination: '/my-url/here/', // Required string: the URL destination of a redirect
  basePath: true, // Optional boolean (defaults to true): whether to use the Next.js base path.
}

Or a function that receives { ctx, AuthUser } and returns a string or RedirectObject:

const redirect = ({ ctx, AuthUser }) => {
  // any custom logic here
  return `/my-url/here/?username=${AuthUser.displayName}`
}

The ctx is the Next.js context value if server side, or undefined if client side.

Examples

Adding a private key to Vercel

There are various ways to add your Firebase private key as an environment variable to Vercel.

Vercel console

In the Vercel console, add the private key in double quotes (screenshot here).

Then, use the private key in your next-firebase-auth config, in the firebaseAdminInitConfig.credential.privateKey property:

privateKey: process.env.FIREBASE_PRIVATE_KEY

Vercel CLI

Via the Vercel CLI, add the private key with double quotes:

vercel secrets add firebase-private-key '"my-key-here"'

Then, use JSON.parse in the firebaseAdminInitConfig.credential.privateKey property:

privateKey: process.env.FIREBASE_PRIVATE_KEY
  ? JSON.parse(process.env.FIREBASE_PRIVATE_KEY)
  : undefined

Alternative formatting

Others have taken different approaches to deal with escaped newline characters in the private key; for example, by using string replacement. This discussion includes other approaches: discussion #95

Using the Firebase Apps

You may want to access the Firebase admin module or Firebase JS SDK.

To use the Firebase admin module, you can use getFirebaseAdmin. (If you prefer, you can instead choose to initialize Firebase yourself prior to initializing next-firebase-auth. Here's some example code with this pattern.)

To use the Firebase JS SDK, simply import Firebase as you normally would. For example:

import firebase from 'firebase/app'
import 'firebase/firestore'
import { useEffect } from 'react'

const Artists = () => {
  const [artists, setArtists] = useState(artists)

  useEffect(() => {
    return firebase
      .firestore()
      .collection('artists')
      .onSnapshot((snap) => {
        if (!snap) {
          return
        }
        setArtists(snap.docs.map((doc) => ({ ...doc.data(), key: doc.id })))
      })
  }, [])

  return (
    <div>
      {artists.map((artist) => (
        <div>{artist.name}</div>
      ))}
    </div>
  )
}

TypeScript

When using withAuthUser with TypeScript, use TypeScript Generics. For example:

// /pages/demo.tsx
import { VFC } from 'react'
import { Loading } from 'components/Loading/Loading'
import { AuthAction, withAuthUser } from 'next-firebase-auth'

type DemoDataType = {
  name: string
}

const Demo: VFC<DemoDataType> = ({ name }) => {
  return <div>Hello {name}!</div>
}

export default withAuthUser<DemoDataType>({ // <--- Ensure that the type is provided
  whenUnauthedBeforeInit: AuthAction.SHOW_LOADER,
  whenUnauthedAfterInit: AuthAction.REDIRECT_TO_LOGIN,
  LoaderComponent: Loading,
})(Demo)

For a full example with server-side data fetching, see the TypeScript demo page in the example app.

Dynamic Redirects

This package makes it easy to redirect to a login page or app page depending on whether a user is logged in. The destination URLs can also be dynamic: the PageURL can be a function that returns the URL at runtime.

The example app uses this to set a post-login destination URL:

// ./utils/initAuth.js
import { init } from 'next-firebase-auth'
import absoluteUrl from 'next-absolute-url'

const initAuth = () => init({
  // This demonstrates setting a dynamic destination URL when
  // redirecting from app pages. Alternatively, you can simply
  // specify `authPageURL: '/auth-ssr'`.
  authPageURL: ({ ctx }) => {
    const isServerSide = typeof window === 'undefined'
    const origin = isServerSide
      ? absoluteUrl(ctx.req).origin
      : window.location.origin
    const destPath =
      typeof window === 'undefined' ? ctx.resolvedUrl : window.location.href
    const destURL = new URL(destPath, origin)
    return `auth-ssr?destination=${encodeURIComponent(destURL)}`
  },

  // This demonstrates setting a dynamic destination URL when
  // redirecting from auth pages. Alternatively, you can simply
  // specify `appPageURL: '/'`.
  appPageURL: ({ ctx }) => {
    const isServerSide = typeof window === 'undefined'
    const origin = isServerSide
      ? absoluteUrl(ctx.req).origin
      : window.location.origin
    const params = isServerSide
      ? new URL(ctx.req.url, origin).searchParams
      : new URLSearchParams(window.location.search)
    const destinationParamVal = params.get('destination')
      ? decodeURIComponent(params.get('destination'))
      : undefined

    // By default, go to the index page if the destination URL
    // is invalid or unspecified.
    let destURL = '/'
    if (destinationParamVal) {
      // Verify the redirect URL host is allowed.
      // https://owasp.org/www-project-web-security-testing-guide/v41/4-Web_Application_Security_Testing/11-Client_Side_Testing/04-Testing_for_Client_Side_URL_Redirect
      const allowedHosts = ['localhost:3000', 'nfa-example.vercel.app']
      const allowed =
        allowedHosts.indexOf(new URL(destinationParamVal).host) > -1
      if (allowed) {
        destURL = destinationParamVal
      } else {
        // eslint-disable-next-line no-console
        console.warn(
          `Redirect destination host must be one of ${allowedHosts.join(
            ', '
          )}.`
        )
      }
    }
    return destURL
  },

  // ... other config
}

export default initAuth

Testing and Mocking with Jest

To test components wrapped with functions from next-firebase-auth, you will likely want to mock the next-firebase-auth library. This can be achieved using the manual mocks feature of Jest.

It can be helpful to define the default mock behavior of next-firebase-auth across your tests. To do so, stub out the module in a top-level __mocks__ folder (alongside the node_modules in your application):

├── __mocks__
│   └── next-firebase-auth
│       └── index.js
├── node_modules
│   └── ... all your deps
├── src
│   └── ... all your source code

In index.js, export a mock of next-firebase-auth:

const { AuthAction } = require('next-firebase-auth')
const NFAMock = jest.createMockFromModule('next-firebase-auth')

module.exports = {
  ...NFAMock,
  // Customize any mocks as needed.
  init: jest.fn(),
  // For example, in tests, this will automatically render the child component of
  // `withAuthUser`.
  withAuthUser: jest.fn(() => (wrappedComponent) => wrappedComponent),
  useAuthUser: jest.fn(() => ({
    // ... you could return a default AuthUser here
  }),
  AuthAction,
}

See our implementation of this in our tab-web repository for a more robust example.

You will also likely want to have a utility to mock the AuthUser object that is passed around via the hooks and higher-order functions in next-firebase-auth. You might put this in a utils folder in your app.

// Create a mock FirebaseUser instance with the fields that you use.
const mockFirebaseUser = {
  displayName: 'Banana Manana',
  // ... other fields from firebaseUser that you may use
}

/**
 * Build and return a dummy AuthUser instance to use in tests.
 *
 * @arg {boolean} isLoggedIn - Pass `false` to mimic a logged out user.
 * @returns {AuthUserContext} - A mocked AuthUser instance, with 'serialize' added.
 */
const getMockAuthUser = (isLoggedIn = true) => ({
  id: isLoggedIn ? 'abcd1234' : null,
  email: isLoggedIn ? 'banana@banana.com' : null,
  emailVerified: isLoggedIn,
  getIdToken: jest.fn(async () => (isLoggedIn ? 'i_am_a_token' : null)),
  clientInitialized: isLoggedIn,
  firebaseUser: isLoggedIn ? mockFirebaseUser : null,
  signOut: jest.fn(),
  serialize: jest.fn(() => 'serialized_auth_user'),
})

export default getMockAuthUser

Now, you can use and customize the mock behavior in your tests.

If you're modifying higher-order functions, components being tested need to be required inside a beforeEach function or each test case. This is because mocking next-firebase-auth has to happen before your component is imported, because the call to the next-firebase-auth function is part of the default export of your component (e.g., export default withAuthUser()(MyComponent)).

Given the following component:

import React from 'react'
import { useAuthUser, withAuthUser } from 'next-firebase-auth'

function UserDisplayName() {
  const AuthUser = useAuthUser()
  const { displayName = 'anonymous' } = AuthUser.firebaseUser
  return <span>{displayName}</span>
}

export default withAuthUser()(UserDisplayName)

you can write a test suite like this:

import { render, screen } from '@testing-library/react'

// Import the functions that the component module calls, which allows jest to mock them
// in the context of this test run. This allows you to manipulate the return value of each
// function within this test suite.
import { useAuthUser, withAuthUser } from 'next-firebase-auth'

// Import your mock AuthUser generator
import getMockAuthUser from '../../utils/test-utils/get-mock-auth-user'

// Mock all of `next-firebase-auth`. This is *not* necessary if you set up manual mocks,
// because Jest will automatically mock the module in every test.
jest.mock('next-firebase-auth')

describe('UserDisplayName', () => {

  // Create a placeholder for your component that you want to test
  let UserDisplayName

  beforeEach(() => {
    // Mock the functions that your component uses, and import your component before each test.
    useAuthUser.mockReturnValue(getMockAuthUser())
    withAuthUser.mockImplementation(() => (wrappedComponent) => wrappedComponent))
    UserDisplayName = require('./').default
  })

  afterAll(() => {
    // Reset the mocks so that they don't bleed into the next test suite.
    jest.resetAllMocks()
  })

  it('renders the logged in user\'s display name', () => {
    // The default value for the mocked implementation of `withAuthUser` is a fully logged in and verified
    // user. Rendering your component directly with the setup above will result in a "logged in" user being
    // passed to your component.
    render(<UserDisplayName />)
    expect(screen.queryByTest(getMockAuthUser().firebaseUser.displayName)).toBeInTheDocument()
  })

  it('renders "anonymous" when user is not logged in', () => {
    // If you want to test a "logged out" state, then you can mock the function again inside any test,
    // passing a falsy value to `getMockAuthUser`, which will return a logged out AuthUser object.
    useAuthUser.mockReturnValue(getMockAuthUser(false))
    render(<Header />)
    expect(screen.getByText('anonymous')).toBeInTheDocument()
  })
})

Mocks and Typescript

When using TypeScript for your test files, you will have to cast the mocked functions to get access to the mockImplementation and mockReturnValue methods. If we were to rewrite the above example in TS, it might look something like this:

import type { ComponentType } from 'react'
import { render, screen } from '@testing-library/react'

// Import the functions that the component module calls, which allows jest to mock them
// in the context of this test run. This allows you to manipulate the return value of each
// function within this test suite.
import { useAuthUser, withAuthUser } from 'next-firebase-auth'

// Import your mock AuthUser generator
import getMockAuthUser from '../../utils/test-utils/get-mock-auth-user'

// Mock all of `next-firebase-auth`. This is *not* necessary if you set up manual mocks,
// because Jest will automatically mock the module
jest.mock('next-firebase-auth')

describe('UserDisplayName', () => {

  // Create a placeholder for your component that you want to test
  let UserDisplayName: ComponentType

  beforeEach(() => {
    // Mock the functions that your component uses, and import your component before each test.
    (useAuthUser as jest.Mock).mockReturnValue(getMockAuthUser())
    (withAuthUser as jest.Mock).mockImplementation(() => (wrappedComponent: ComponentType) => wrappedComponent: ComponentType))
    UserDisplayName = require('./').default as ComponentType
  })

  afterAll(() => {
    // Reset the mocks so that they don't bleed into the next test suite.
    jest.resetAllMocks()
  })

  it('renders the logged in user\'s display name', () => {
    // The default value for the mocked implementation of `withAuthUser` is a fully logged in and verified
    // user. Rendering your component directly with the setup above will result in a "logged in" user being
    // passed to your component.
    render(<UserDisplayName />)
    expect(screen.getByText(getMockAuthUser().firebaseUser.displayName)).toBeInTheDocument()
  })

  it('renders "anonymous" when user is not logged in', () => {
    // If you want to test a "logged out" state, then you can mock the function again inside any test,
    // passing a falsy value to `getMockAuthUser`, which will return a logged out AuthUser object.
    (useAuthUser as jest.Mock).mockReturnValue(getMockAuthUser(false))
    render(<Header />)
    expect(screen.getByText('anonymous')).toBeInTheDocument()
  })
})

Troubleshooting

Stuck? Search discussions or open your own Q&A discussion describing what you've already tried.

I get the error "[Some setting] should not be available on the client side."

We expect certain sensitive config values to be falsy on the client side (see the config validation code). This is a precaution to make sure developers aren't accidentally bundling something like their Firebase private key with client JS.

To fix this, ensure the config setting is undefined on the client side by logging it to your browser console. You can use Next's .env support to set server-only variables. Never use the NEXT_PUBLIC* prefix for any secret values.

I get an "INVALID_CUSTOM_TOKEN" error when trying to get a refresh token.

This package will call a Google endpoint when it needs to refresh a token server side. You're seeing an error from that request.

To fix this, confirm that your firebaseAdminInitConfig.credential.clientEmail is correct. It should be the email paired with your Firebase private key.

If that doesn't help, try inspecting the custom token to manually validate the values and structure. Some people encounter this problem when their server time is incorrect.

Server-side auth is not working. The user and token are always null when using withAuthUserTokenSSR, but client-side auth works.

If auth is working on the client side but not on the server side, the auth cookies are most likely not set.

To fix this, confirm the auth cookies are set in your browser's dev tools. If they're not set, please check that the secure, sameSite, and path options passed in the next-firebase-auth config make sense for your environment. For example, if you're testing on non-HTTPS localhost, make sure secure is false.

In addition, please double-check your server logs for any errors to ensure the Firebase admin app is initializing properly.

I get an "auth/argument-error" with message "Firebase ID token has invalid signature".

Often, this is caused by an incorrect email in Firebase credentials. Please verify that the email is correct and is from the same Firebase account as your private key, or try generating a new key: https://firebase.google.com/docs/admin/setup

You can try setting up your credentials in the example app to be sure your app code isn't a problem.

In local development, try clearing data/cookies for localhost in case you previously signed in with another Firebase account and still have auth cookies signed by another private key.

You can also try disabling the Firebase Authentication Emulator. Remove firebaseAuthEmulatorHost from your config and remove FIREBASE_AUTH_EMULATOR_HOST from your .env file.

I get the error, "Failed to parse private key: Error: Invalid PEM formatted message."

See adding a private key to Vercel and this discussion on private key formatting.

Limitations & Feedback

We expect some apps will need some features that are not currently available:

  • Supporting custom session logic: Currently, this package doesn't allow using a custom cookie or session module. Some developers may need this flexibility to, for example, keep auth user data in server-side session storage.
  • Setting a single auth cookie: This package currently sets more than one cookie to store authentication state. It's not currently possible to use a single cookie with a customized name: #190

We'd love to hear your feedback on these or other features. Please feel free to open a discussion!

Contributing

We welcome contributions! Please see contributing docs to get started.

Download details:

Author: gladly-team
Source code: https://github.com/gladly-team/next-firebase-auth
License: MIT license

#nextjs #react #reactjs #javascript #auth #firebase

Simple Firebase Authentication for All Next.js Rendering Strategies

Next-auth-mui: Sign-in Dialog for NextAuth Built with MUI and React

next-auth-mui

Sign-in dialog for NextAuth built with MUI and React. Detects configured OAuth and Email providers and renders buttons or input fields for each respectively. Fully themeable, extensible and customizable to support custom credential flows.

Storybook - Examples

Getting started

Install

npm install next-auth-mui

yarn add next-auth-mui

❗Note: NextAuth needs to be configured and MUI has to be installed in your project.

Usage

Simply render the <NextAuthDialog /> component in your app. This component will automatically detect the configured providers by sending a request to the /api/auth/providers endpoint and render the appropriate sign-in buttons or input fields.

import React from 'react';
import { Button } from '@mui/material';
import NextAuthDialog from 'next-auth-mui';

const Example = () => {
  const [open, setOpen] = React.useState(false);
  return (
    <>
      <NextAuthDialog open={open} onClose={() => setOpen(false)} />

      <Button onClick={() => setOpen(true)}>
        Sign-in
      </Button>
    </>
  );
}

Customization

Components rendered within the next-auth-mui dialog are customizable through passing the standard props supported by the respective @mui/material components.

If you need to implement custom logic for fetching providers or want complete control over the sign-in dialog, you can also import the AuthDialog component.

import { AuthDialog } from 'next-auth-mui';

Custom email authentication

A common use-case is using a 3rd party email authentication service to send magic links alongside NextAuth's OAuth providers. In this case you can implement a custom email submit handler.

In the example below we're using magic.link to send emails and a custom credentials provider to authenticate the user.

Additionally, a custom email validator is included to only allow emails that end in @gmail.com.

import NextAuthDialog, { isValidEmail } from 'next-auth-mui';

<NextAuthDialog
  open
  {/* Render email field even if there is no email provider configured */}
  alwaysShowEmailField
  emailValidator={(email) => isValidEmail(email) && email.endsWith('@gmail.com')}
  {/* Custom email submit handler */}
  onSubmitEmail={async (email) => {
    // Send magic link
    const didToken = await magic.auth.loginWithMagicLink({ email });

    // sign in with NextAuth
    await signIn(`credentials`, {
      didToken,
      callbackUrl: router.query[`callbackUrl`]
    });
  }}
/>

All options

export type NextAuthDialogProps = AuthDialogProps & {
  /**
   * Disable sorting of providers by name when rendering their buttons.
   */
  disableSortByName?: boolean;
  /**
   * The endpoint of NextAuth server. Defaults to `/api/auth/providers`.
   */
  url?: string;
}

export type AuthDialogProps = PropsWithChildren<{
  /**
   * See @mui/material documentation
   */
  ButtonProps?: ButtonProps,
  /**
   * See @mui/material documentation
   */
  ButtonTypographyProps?: TypographyProps,
  /**
   * See @mui/material documentation
   */
  DialogContentProps?: DialogContentProps;
  /**
   * See @mui/material documentation
   */
  DialogContentTextProps?: DialogContentTextProps
  /**
   * See @mui/material documentation
   */
  DialogProps?: DialogProps;
  /**
   * See @mui/material documentation
   */
  DialogTitleProps?: DialogTitleProps;
  /**
   * Props passed to the email input field. See @mui/material documentation
   */
  EmailFieldProps?: TextFieldProps;
  /**
   * Props to pass to the default loading indicator. See @mui/material documentation
   */
  LinearProgressProps?: LinearProgressProps;
  /**
   * A custom loading indicator.
   */
  Progress?: React.ReactNode;
  /**
   * Always show the email field regardless if email provider has been configured.
   * This is useful for implementing email auth with a 3rd party api.
   */
  alwaysShowEmailField?: boolean;
  /**
   * Controls width of dialog.
   * When breakpoint >= viewport the dialog will be rendered in mobile mode.
   * Defaults to `xs`.
   */
  breakpoint?: Breakpoint,
  /**
   * Disable autofocus of email field.
   */
  disableEmailAutoFocus?: boolean;
  /**
   * Text to display between email field and oauth buttons. Defaults to "or".
   */
  dividerText?: string | React.ReactNode;
  /**
   * Render error text instead of providers
   */
  error?: string,
  /**
   * Hide the provider icons on their buttons.
   */
  hideProviderIcon?: boolean;
  /**
   * Hide the provider names on their buttons.
   */
  hideProviderName?: boolean;
  /**
   * Hide the dialog title. In mobile mode this will hide the close "x" icon.
   */
  hideTitle?: boolean;
  /**
   * Custom email validation function.
   */
  isValidEmail?: (email: string) => boolean | Promise<boolean>;
  /**
   * If true a loading indicator will be displayed in the dialog.
   */
  loading?: boolean;
  /**
   * Callback for closing the dialog.
   */
  onClose?: () => void;
  /**
   * Callback runs on a failed sign in.
   */
  onOAuthSignInError?: (error: Error) => void;
  /**
   * Callback runs on a successful sign in.
   */
  onOAuthSignInSuccess?: (response: SignInResponse | undefined) => void;
  /**
   * Override default email submission function.
   * This is useful for implementing authentication with a 3rd party API like MagicLink.
   */
  onSubmitEmail?: (email: string) => Promise<void>;
  /**
   * When true the dialog will be open.
   */
  open: boolean,
  /**
   * An object mapping of provider id to provider config.
   */
  providers?: Record<string, ProviderConfig>;
  /**
   * Additional sign in options to be passed when calling `signIn`.  See next-auth for documentation
   */
  signInOptions?: SignInOptions;
  /**
   * Text to display in the dialog title. Empty by default.
   */
  titleText?: string | React.ReactNode;
}>

export type OauthProviderConfig = {
  /**
   * Override props passed to provider's button. See @mui/material documentation.
   */
  ButtonProps?: ButtonProps
  /**
   * Override props passed to provider's button's typography. See @mui/material documentation.
   */
  ButtonTypographyProps?: TypographyProps
  /**
   * Override props passed to provider's icon. See @iconify/react documentation.
   */
  IconProps?: IconProps;
  /**
   * Hide the provider icon on button.
   */
  hideProviderIcon?: boolean;
  /**
   * Hide the provider names button.
   */
  hideProviderName?: boolean;
  /**
   * Override the provider's icon. Can be a @iconify/react icon name or a custom component.
   */
  icon?: string | React.ReactNode;
  /**
   * Override the provider's name when rendering the button.
   */
  label?: string;
}

export type EmailProviderConfig = {
  /**
   * Override props passed to the email's input field. See @mui/material documentation.
   */
  EmailFieldProps?: TextFieldProps,
  /**
   * Override end icon rendered in the email input field
   */
  endIcon?: React.ReactNode;
  /**
   * Override text rendered below the email input field.
   */
  helperText?: string | React.ReactNode;
  /**
   * Override the placeholder text rendered in the email input field.
   */
  placeholder?: string;
  /**
   * Override start icon rendered in the email input field
   */
  startIcon?: React.ReactNode;
}

export type ProviderConfig = OauthProviderConfig & EmailProviderConfig & {
  /**
   * ID of the provider.
   */
  id: string;
  /**
   * Name of the provider. Will be used as the button's label and used when sorting providers.
   */
  name: string;
  /**
   * Override sign in options to be passed when calling `signIn`.  See next-auth for documentation
   */
  signInOptions?: SignInOptions;
  /**
   * Type of the provider.
   * Only `email` and `oauth` are supported, all other types will be ignored when rendering fields.
   */
  type: 'oauth' | 'email' | string;
};

Download details:

Author: TimMikeladze
Source code: https://github.com/TimMikeladze/next-auth-mui
License: MIT license

#nextjs #react #reactjs #javascript #auth #oauth #typescript

Next-auth-mui: Sign-in Dialog for NextAuth Built with MUI and React
Joseph  Murray

Joseph Murray

1660844580

SvelteKit Auth: Authentication library for use with SvelteKit

SvelteKitAuth

Authentication library for use with SvelteKit featuring built-in OAuth providers and zero restriction customization!

Installation

SvelteKitAuth is available on NPM as sk-auth, it can be installed with NPM:

npm i sk-auth --save

Or Yarn:

yarn add sk-auth

Usage with Typescript

SvelteKitAuth also comes with first-class support for Typescript out of the box, so no need to add an additional @types/ dev dependency! 🎉

Getting Started

SvelteKitAuth is very easy to setup! All you need to do is instantiate the SvelteKitAuth class, and configure it with some default providers, as well as a JWT secret key used to verify the cookies:

Warning: env variables prefixed with VITE_ can be exposed and leaked into client-side bundles if they are referenced in any client-side code. Make sure this is not the case, or consider using an alternative method such as loading them via dotenv directly instead.

export const appAuth = new SvelteKitAuth({
  providers: [
    new GoogleOAuthProvider({
      clientId: import.meta.env.VITE_GOOGLE_OAUTH_CLIENT_ID,
      clientSecret: import.meta.env.VITE_GOOGLE_OAUTH_CLIENT_SECRET,
      profile(profile) {
        return { ...profile, provider: "google" };
      },
    }),
  ],
  jwtSecret: import.meta.env.JWT_SECRET_KEY,
});

If you want to override or augment the default SvelteKit session to get access to the user in the session store, you can use the getSession hook:

// overriding the default session
export const { getSession } = appAuth;

// augmenting it
export const getSession: GetSession = async (request) => {
  const { user } = await appAuth.getSession(request);

  return { user };
};

Callbacks

SvelteKitAuth provides some callbacks, similar to NextAuth.js. Their call signatures are:

interface AuthCallbacks {
  signIn?: () => boolean | Promise<boolean>;
  jwt?: (token: JWT, profile?: any) => JWT | Promise<JWT>;
  session?: (token: JWT, session: Session) => Session | Promise<Session>;
  redirect?: (url: string) => string | Promise<string>;
}

Adding more Providers

SvelteKitAuth uses a object-oriented approach towards creating providers. It is unopionated and allows you to implement any three-legged authentication flow such as OAuth, SAML SSO, and even regular credential logins by omitting the signin() route.

You can implement your own using the Provider base provider class, and by implementing the signin() and callback() methods:

export abstract class Provider<T extends ProviderConfig = ProviderConfig> {
  abstract signin<Locals extends Record<string, any> = Record<string, any>, Body = unknown>(
    request: ServerRequest<Locals, Body>,
  ): EndpointOutput | Promise<EndpointOutput>;

  abstract callback<Locals extends Record<string, any> = Record<string, any>, Body = unknown>(
    request: ServerRequest<Locals, Body>,
  ): CallbackResult | Promise<CallbackResult>;
}

signin() must return a generic endpoint output, this can be a redirect, or the path to the provider's sign-in page. When implementing a HTTP POST route, signin() can simply return an empty body and callback() should handle the user login flow.

callback() takes a ServerRequest and must return a CallbackResult which is a custom type exported by svelte-kit-auth:

export type Profile = any;
export type CallbackResult = [Profile, string | null];

The first item in the tuple is the user profile, which gets stored in the token, and is provided to the jwt() callback as the second argument. The second item is a redirect route, which may be tracked using the state query parameter for OAuth providers, or other implementations depending on the sign-in method.

OAuth2

SvelteKitAuth comes with a built-in OAuth2 provider that takes extensive configuration parameters to support almost any common OAuth2 provider which follows the OAuth2 spec. It can be imported from sk-auth/providers and configured with the following configuration object:

export interface OAuth2ProviderConfig<ProfileType = any, TokensType extends OAuth2Tokens = any>
  extends OAuth2BaseProviderConfig<ProfileType, TokensType> {
  accessTokenUrl?: string;
  authorizationUrl?: string;
  profileUrl?: string;
  clientId?: string;
  clientSecret?: string;
  scope: string | string[];
  headers?: any;
  authorizationParams?: any;
  params: any;
  grantType?: string;
  responseType?: string;
  contentType?: "application/json" | "application/x-www-form-urlencoded";
}

Some values have defaults which can be seen below:

const defaultConfig: Partial<OAuth2ProviderConfig> = {
  responseType: "code",
  grantType: "authorization_code",
  contentType: "application/json",
};

The OAuth2Provider class can then be instantiated with the configuration to support the OAuth2 flow, including authorization redirect, token retrieval and profile fetching. It will also automatically handle the state and nonce params for you.

Motivation

SvelteKitAuth is inspired by the NextAuth.js package built for the Next.js SSR framework for React. Unlike NextAuth.js it is completely unopinionated and only provides implementations for default flows, while still empowering users to add their own providers.

As it leverages classes and Typescript, the implementation of such providers is very straightforward, and in the future it will even be possible to register multiple SvelteKitAuth handlers in the same project, should the need arise, by leveraging a class-based client and server setup.

Examples

Looking for help? Check out the example app in the repository source. Make something cool you want to show off? Share it with others in the discussion section.

Contributing

🚧 Work in Progress!

Download details:

Author: Dan6erbond
Source code: https://github.com/Dan6erbond/sk-auth
License: MIT license

#svetle #javascript #auth #oauth 

SvelteKit Auth: Authentication library for use with SvelteKit

Firebase Phone Auth Handler For Flutter

FirebasePhoneAuthHandler For Flutter

  • An easy-to-use firebase phone authentication package to easily send and verify OTP's with auto-fetch OTP support via SMS.
  • Supports OTP on web out of the box.

Screenshots

           

Getting Started

Step 1: Before you can add Firebase to your app, you need to create a Firebase project to connect to your application. Visit Understand Firebase Projects to learn more about Firebase projects.

Step 2: To use Firebase in your app, you need to register your app with your Firebase project. Registering your app is often called "adding" your app to your project.

Also, register a web app if using on the web. Follow on the screen instructions to initialize the project.

Add the latest version 'firebase-auth' CDN from here. (Tested on version 8.6.1)

Step 3: Add a Firebase configuration file and the SDK's. (google-services)

Step 4: When the basic setup is done, open the console and then the project and head over to Authentication from the left drawer menu.

Step 5: Click on Sign-in method next to the Users tab and enable Phone.

Step 6: Follow the additional configuration steps for the platforms to avoid any errors.

Step 7: IMPORTANT: Do not forget to enable the Android Device Verification service from Google Cloud Platform. (make sure the correct project is selected).

Step 8: Lastly, add firebase_core as a dependency in your pubspec.yaml file. and call Firebase.initializeApp() in the main method as shown:

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await Firebase.initializeApp();
  runApp(_MainApp());
}

Usage

To use this plugin, add firebase_phone_auth_handler as a dependency in your pubspec.yaml file.

  dependencies:
    flutter:
      sdk: flutter
    firebase_phone_auth_handler:

First and foremost, import the widget.

import 'package:firebase_phone_auth_handler/firebase_phone_auth_handler.dart';

Wrap the MaterialApp with FirebasePhoneAuthProvider to enable your application to support phone authentication like shown.

class _MainApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return FirebasePhoneAuthProvider(
      child: MaterialApp(
        debugShowCheckedModeBanner: false,
        home: HomeScreen(),
      ),
    );
  }
}

You can now add a FirebasePhoneAuthHandler widget to your widget tree and pass all the required parameters to get started.

FirebasePhoneAuthHandler(
    phoneNumber: "+919876543210",
    builder: (context, controller) {
        return SizedBox.shrink();
    },
),

The phone number is the number to which the OTP will be sent which should be formatted in the following way:

+919876543210 - where +91 is the country code and 9876543210 is the phone number.

The widget returned from the builder is rendered on the screen. The builder exposes a controller which contains various variables and methods.

Callbacks such as onLoginSuccess or onLoginFailed can be passed to the widget.

onLoginSuccess is called whenever the otp was sent to the mobile successfully and was either auto verified or verified manually by calling verifyOTP function in the controller. The callback exposes UserCredential object which can be used to find user UID and other stuff. The boolean provided is whether the OTP was auto verified or verified manually be calling verifyOTP. True if auto verified and false is verified manually.

onLoginFailed is called if an error occurs while sending OTP or verifying the OTP or any internal error occurs, callback is triggered exposing FirebaseAuthException which can be used to handle the error.

onCodeSent is called when the OTP is successfully sent to the phone number.

FirebasePhoneAuthHandler(
    phoneNumber: "+919876543210",
    // If true, the user is signed out before the onLoginSuccess callback is fired when the OTP is verified successfully.
    signOutOnSuccessfulVerification: false,
    
    linkWithExistingUser: false,
    builder: (context, controller) {
      return SizedBox.shrink();
    },
    onLoginSuccess: (userCredential, autoVerified) {
      debugPrint("autoVerified: $autoVerified");
      debugPrint("Login success UID: ${userCredential.user?.uid}");
    },
    onLoginFailed: (authException, stackTrace) {
      debugPrint("An error occurred: ${authException.message}");
    },
    onError: (error, stackTrace) {},
),

To logout the current user(if any), simply call

await FirebasePhoneAuthHandler.signOut(context);

controller.signOut() can also be used to logout the current user if the functionality is needed in the same screen as the widget itself (where controller is the variable passed in the callback from the builder method in the widget).

Web (reCAPTCHA)

By default, the reCAPTCHA widget is a fully managed flow which provides security to your web application. The widget will render as an invisible widget when the sign-in flow is triggered. An "invisible" widget will appear as a full-page modal on-top of your application like demonstrated below.

reCAPTCHA1

Although, a RecaptchaVerifier instance can be passed which can be used to manage the widget.

Use the function recaptchaVerifierForWebProvider in FirebasePhoneAuthHandler which gives a boolean to check whether the current platform is Web or not.

NOTE: Do not pass a RecaptchaVerifier instance if the platform is not web, else an error occurs.

Example:

recaptchaVerifierForWebProvider: (isWeb) {
    if (isWeb) return RecaptchaVerifier();
},

It is however possible to display an inline widget which the user has to explicitly press to verify themselves.

reCAPTCHA2

To add an inline widget, specify a DOM element ID to the container argument of the RecaptchaVerifier instance. The element must exist and be empty otherwise an error will be thrown. If no container argument is provided, the widget will be rendered as "invisible".

RecaptchaVerifier(
  container: 'recaptcha',
  size: RecaptchaVerifierSize.compact,
  theme: RecaptchaVerifierTheme.dark,
  onSuccess: () => print('reCAPTCHA Completed!'),
  onError: (FirebaseAuthException error) => print(error),
  onExpired: () => print('reCAPTCHA Expired!'),
),

If the reCAPTCHA badge does not disappear automatically after authentication is done, try adding the following code in onLoginSuccess so that it disappears when the login process is done.

Firstly import querySelector from dart:html.

import 'dart:html' show querySelector;

Then add this in onLoginSuccess callback.

final captcha = querySelector('#__ff-recaptcha-container');
if (captcha != null) captcha.hidden = true;

If you want to completely disable the reCAPTCHA badge (typically appears on the bottom right), add this CSS style in the web/index.html outside any other tag.

<style>
    .grecaptcha-badge { visibility: hidden; }
</style>

How I prefer using it usually

I usually have a phone number input field, which handles phone number input. Then pass the phone number to the VerifyPhoneNumberScreen widget from the example app.

// probably some ui or dialog to get the phone number
final phoneNumber = _getPhoneNumber();

// then call
void _verifyPhoneNumber() async {
  Navigator.push(
    context,
    MaterialPageRoute(
      builder: (_) => VerifyPhoneNumberScreen(phoneNumber: phoneNumber),
    ),
  );
}

/// route to home screen or somewhere in the onLoginSuccess callback for [VerifyPhoneNumberScreen] 

Sample Usage

import 'package:firebase_phone_auth_handler/firebase_phone_auth_handler.dart';
import 'package:flutter/material.dart';
import 'package:phone_auth_handler_demo/screens/home_screen.dart';
import 'package:phone_auth_handler_demo/utils/helpers.dart';
import 'package:phone_auth_handler_demo/widgets/custom_loader.dart';
import 'package:phone_auth_handler_demo/widgets/pin_input_field.dart';

class VerifyPhoneNumberScreen extends StatefulWidget {
  static const id = 'VerifyPhoneNumberScreen';

  final String phoneNumber;

  const VerifyPhoneNumberScreen({
    Key? key,
    required this.phoneNumber,
  }) : super(key: key);

  @override
  State<VerifyPhoneNumberScreen> createState() =>
      _VerifyPhoneNumberScreenState();
}

class _VerifyPhoneNumberScreenState extends State<VerifyPhoneNumberScreen>
    with WidgetsBindingObserver {
  bool isKeyboardVisible = false;

  late final ScrollController scrollController;

  @override
  void initState() {
    scrollController = ScrollController();
    WidgetsBinding.instance.addObserver(this);
    super.initState();
  }

  @override
  void dispose() {
    WidgetsBinding.instance.removeObserver(this);
    scrollController.dispose();
    super.dispose();
  }

  @override
  void didChangeMetrics() {
    final bottomViewInsets = WidgetsBinding.instance.window.viewInsets.bottom;
    isKeyboardVisible = bottomViewInsets > 0;
  }

  // scroll to bottom of screen, when pin input field is in focus.
  Future<void> _scrollToBottomOnKeyboardOpen() async {
    while (!isKeyboardVisible) {
      await Future.delayed(const Duration(milliseconds: 50));
    }

    await Future.delayed(const Duration(milliseconds: 250));

    await scrollController.animateTo(
      scrollController.position.maxScrollExtent,
      duration: const Duration(milliseconds: 250),
      curve: Curves.easeIn,
    );
  }

  @override
  Widget build(BuildContext context) {
    return SafeArea(
      child: FirebasePhoneAuthHandler(
        phoneNumber: widget.phoneNumber,
        signOutOnSuccessfulVerification: false,
        linkWithExistingUser: false,
        autoRetrievalTimeOutDuration: const Duration(seconds: 60),
        otpExpirationDuration: const Duration(seconds: 60),
        onCodeSent: () {
          log(VerifyPhoneNumberScreen.id, msg: 'OTP sent!');
        },
        onLoginSuccess: (userCredential, autoVerified) async {
          log(
            VerifyPhoneNumberScreen.id,
            msg: autoVerified
                ? 'OTP was fetched automatically!'
                : 'OTP was verified manually!',
          );

          showSnackBar('Phone number verified successfully!');

          log(
            VerifyPhoneNumberScreen.id,
            msg: 'Login Success UID: ${userCredential.user?.uid}',
          );

          Navigator.pushNamedAndRemoveUntil(
            context,
            HomeScreen.id,
            (route) => false,
          );
        },
        onLoginFailed: (authException, stackTrace) {
          log(
            VerifyPhoneNumberScreen.id,
            msg: authException.message,
            error: authException,
            stackTrace: stackTrace,
          );

          switch (authException.code) {
            case 'invalid-phone-number':
              // invalid phone number
              return showSnackBar('Invalid phone number!');
            case 'invalid-verification-code':
              // invalid otp entered
              return showSnackBar('The entered OTP is invalid!');
            // handle other error codes
            default:
              showSnackBar('Something went wrong!');
            // handle error further if needed
          }
        },
        onError: (error, stackTrace) {
          log(
            VerifyPhoneNumberScreen.id,
            error: error,
            stackTrace: stackTrace,
          );

          showSnackBar('An error occurred!');
        },
        builder: (context, controller) {
          return Scaffold(
            appBar: AppBar(
              leadingWidth: 0,
              leading: const SizedBox.shrink(),
              title: const Text('Verify Phone Number'),
              actions: [
                if (controller.codeSent)
                  TextButton(
                    onPressed: controller.isOtpExpired
                        ? () async {
                            log(VerifyPhoneNumberScreen.id, msg: 'Resend OTP');
                            await controller.sendOTP();
                          }
                        : null,
                    child: Text(
                      controller.isOtpExpired
                          ? 'Resend'
                          : '${controller.otpExpirationTimeLeft.inSeconds}s',
                      style: const TextStyle(color: Colors.blue, fontSize: 18),
                    ),
                  ),
                const SizedBox(width: 5),
              ],
            ),
            body: controller.isSendingCode
                ? Column(
                    mainAxisAlignment: MainAxisAlignment.center,
                    crossAxisAlignment: CrossAxisAlignment.center,
                    children: const [
                      CustomLoader(),
                      SizedBox(height: 50),
                      Center(
                        child: Text(
                          'Sending OTP',
                          style: TextStyle(fontSize: 25),
                        ),
                      ),
                    ],
                  )
                : ListView(
                    padding: const EdgeInsets.all(20),
                    controller: scrollController,
                    children: [
                      Text(
                        "We've sent an SMS with a verification code to ${widget.phoneNumber}",
                        style: const TextStyle(fontSize: 25),
                      ),
                      const SizedBox(height: 10),
                      const Divider(),
                      if (controller.isListeningForOtpAutoRetrieve)
                        Column(
                          children: const [
                            CustomLoader(),
                            SizedBox(height: 50),
                            Text(
                              'Listening for OTP',
                              textAlign: TextAlign.center,
                              style: TextStyle(
                                fontSize: 25,
                                fontWeight: FontWeight.w600,
                              ),
                            ),
                            SizedBox(height: 15),
                            Divider(),
                            Text('OR', textAlign: TextAlign.center),
                            Divider(),
                          ],
                        ),
                      const SizedBox(height: 15),
                      const Text(
                        'Enter OTP',
                        style: TextStyle(
                          fontSize: 20,
                          fontWeight: FontWeight.w600,
                        ),
                      ),
                      const SizedBox(height: 15),
                      PinInputField(
                        length: 6,
                        onFocusChange: (hasFocus) async {
                          if (hasFocus) await _scrollToBottomOnKeyboardOpen();
                        },
                        onSubmit: (enteredOtp) async {
                          final verified =
                              await controller.verifyOtp(enteredOtp);
                          if (verified) {
                            // number verify success
                            // will call onLoginSuccess handler
                          } else {
                            // phone verification failed
                            // will call onLoginFailed or onError callbacks with the error
                          }
                        },
                      ),
                    ],
                  ),
          );
        },
      ),
    );
  }
}

See the example directory for a complete sample app.

Created & Maintained By Rithik Bhandari

Use this package as a library

Depend on it

Run this command:

With Flutter:

 $ flutter pub add firebase_phone_auth_handler

This will add a line like this to your package's pubspec.yaml (and run an implicit flutter pub get):

dependencies:
  firebase_phone_auth_handler: ^1.0.6

Alternatively, your editor might support flutter pub get. Check the docs for your editor to learn more.

Import it

Now in your Dart code, you can use:

import 'package:firebase_phone_auth_handler/firebase_phone_auth_handler.dart'; 

example/lib/main.dart

import 'package:firebase_core/firebase_core.dart';
import 'package:firebase_phone_auth_handler/firebase_phone_auth_handler.dart';
import 'package:flutter/material.dart';
import 'package:phone_auth_handler_demo/firebase_options.dart';
import 'package:phone_auth_handler_demo/screens/splash_screen.dart';
import 'package:phone_auth_handler_demo/utils/app_theme.dart';
import 'package:phone_auth_handler_demo/utils/globals.dart';
import 'package:phone_auth_handler_demo/utils/route_generator.dart';

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform);
  runApp(const _MainApp());
}

class _MainApp extends StatelessWidget {
  const _MainApp({
    Key? key,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return FirebasePhoneAuthProvider(
      child: MaterialApp(
        debugShowCheckedModeBanner: false,
        title: 'FirebasePhoneAuthHandler Demo',
        scaffoldMessengerKey: Globals.scaffoldMessengerKey,
        theme: AppTheme.lightTheme,
        darkTheme: AppTheme.darkTheme,
        onGenerateRoute: RouteGenerator.generateRoute,
        initialRoute: SplashScreen.id,
      ),
    );
  }
} 

Download Details:

Author: rithik-dev

Source Code: https://github.com/rithik-dev/firebase_phone_auth_handler

#flutter #auth #firebase 

Firebase Phone Auth Handler For Flutter

Flutter Package Which Manages The Authentication Domain

Senior X Platform - authentication package

This is a package to handle the Senior X Platform authentication flow.

Use this package as a library

Depend on it

Run this command:

With Flutter:

 $ flutter pub add senior_authentication

This will add a line like this to your package's pubspec.yaml (and run an implicit flutter pub get):

dependencies:
  senior_authentication: ^0.3.3

Alternatively, your editor might support flutter pub get. Check the docs for your editor to learn more.

Import it

Now in your Dart code, you can use:

import 'package:senior_authentication/senior_authentication.dart'; 

example/example.md

Senior Authentication

All the snippets are from the example project.

Simple Usage

void main() {
  runApp(App(
    authenticationRepository: AuthenticationRepository(
        urlBase:
            'https://platform.senior.com.br/t/senior.com.br/bridge/1.0/rest'),
  ));
}
class App extends StatelessWidget {
  const App({Key? key, required this.authenticationRepository})
      : super(key: key);

  final AuthenticationRepository authenticationRepository;

  @override
  Widget build(BuildContext context) {
    SystemChrome.setSystemUIOverlayStyle(
        SystemUiOverlayStyle(statusBarColor: Colors.white));

    return RepositoryProvider.value(
      value: authenticationRepository,
      child: BlocProvider(
        create: (_) => AuthenticationBloc(
          authenticationRepository: authenticationRepository,
        ),
        child: AppView(),
      ),
    );
  }
}

class AppView extends StatefulWidget {
  AppView({Key? key}) : super(key: key);

  @override
  _AppViewState createState() => _AppViewState();
}

class _AppViewState extends State<AppView> {
  final _navigatorKey = GlobalKey<NavigatorState>();

  NavigatorState get _navigator => _navigatorKey.currentState!;

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      navigatorKey: _navigatorKey,
      title: 'Example',
      theme: ThemeData(
        primaryColor: Color(0xFF0E866A),
        visualDensity: VisualDensity.adaptivePlatformDensity,
        scaffoldBackgroundColor: Colors.white,
      ),
      debugShowCheckedModeBanner: false,
      initialRoute: 'splash',
      routes: {
        'splash': (ctx) => SplashScreen(),
        'home': (ctx) => HomeScreen(),
      },
      builder: (context, child) {
        return BlocListener<AuthenticationBloc, AuthenticationState>(
          child: child,
          listener: (context, state) {
            switch (state.status) {
              case AuthenticationStatus.authenticated:
                _navigator.pushNamedAndRemoveUntil<void>(
                  "home",
                  (route) => false,
                );
                break;
              case AuthenticationStatus.unauthenticated:
                _navigator.pushAndRemoveUntil<void>(
                  MaterialPageRoute(builder: (ctx) => WelcomeScreen()),
                  (route) => false,
                );
                break;
              default:
                break;
            }
          },
        );
      },
    );
  }
} 

Download Details:

Author: 

Source Code: https://pub.dev/packages/senior_authentication

#auth #flutter 

Flutter Package Which Manages The Authentication Domain

A Flutter Package to Verify Emails using OTP

Email verification for Flutter Apps using DART.

Key points :

  • This package allows developers to verify that the provided Email is valid and also an existing one,
  • It is confirmed by sending an OTP to the specified email ID and verify them.

Features!

Key changes:

  • No more static methods, All the methods are based on the class instance.
  • More reliable and understandable method names.
  • Change in parameters.
  • Session name is made mandatory.
  • Additional option to set the OTP length for production servers

Steps

Initialize the class

EmailAuth emailAuth =  new EmailAuth(sessionName: "Sample session");

Pass in the remote server config if present

emailAuth.config(remoteServerConfiguration);

// remoteServerConfiguration : Signature
{
  "server": "server url",
  "serverKey": "serverKey"
}

Sending an otp

  • Have the method wrapped in a async funtion.
void sendOtp() async {
  bool result = await emailAuth.sendOtp(
      recipientMail: _emailcontroller.value.text, otpLength: 5
      );
  }

Validating an otp

  • Have the method wrapped in a funtion for better reusablity.
emailAuth.validateOtp(
        recipientMail: _emailcontroller.value.text,
        userOtp: _otpcontroller.value.text)

Usage template example

import 'package:email_auth/email_auth.dart';
...
Inside your stateLess / Statefull widget class
  ...
  
  // Declare the object
  EmailAuth emailAuth;

  @override
  void initState() {
    super.initState();
    // Initialize the package
    emailAuth = new EmailAuth(
      sessionName: "Sample session",
    );

    /// Configuring the remote server
    emailAuth.config(remoteServerConfiguration);
  }

  final TextEditingController _emailController = TextEditingController();
  final TextEditingController _otpController = TextEditingController();

  /// a Boolean function to verify if the Data provided is true
  bool verify() {
    print(emailAuth.validateOtp(
        recipientMail: _emailcontroller.value.text,
        userOtp: _otpcontroller.value.text));
  }

  /// a void funtion to send the OTP to the user
  /// Can also be converted into a Boolean function and render accordingly for providers
  void sendOtp() async {
    bool result = await emailAuth.sendOtp(
        recipientMail: _emailcontroller.value.text, otpLength: 5);
    if (result) {
      // using a void function because i am using a 
      // stateful widget and seting the state from here.
      setState(() {
        submitValid = true;
      });
    }
  }
  
  ...
   Widget build(BuildContext context) {
   /// have your controllers assigned to textFields or textFormFields
   ...
    body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            TextField(
              controller: _emailController,
            ),
            TextField(
              controller: _otpController,
            ),
          ],
        ),
      ),
      ...

Reference

PropertyTypeDescription
EmailAuthClassThe parent Class
EmailAuth.sessionNameStringThe sessionName of the instance to be used
EmailAuth.configBoolean FunctionUsed to verify whether the remote server is valid
EmailAuth.sendOtpBoolean FunctionTakes care of sending OTP to the mail id provided
recipientMailparam of EmailAuth.sentOtp() methodemail ID of the recipient
otpLengthparam of EmailAuth.sentOtp() method : Defaults to 6length of the otp
EmailAuth.validateOtpBoolean FunctionTakes care of verifying the OTP entered by the user

Privacy Policy 😸

We never share the email ID's we get to any service, nor do we use them for our purposes, we regularly clean up the sent mail section, and we never save any data on our servers, we work on the main motive to be OPEN SOURCE , If so you have any queries kindly mail me at the email ID provided Always happy to answer.

⭐ If you like the package, a star to the repo will mean a lot.

Also feel free to fork the main branch and add some additional features, Will be eager to verify and add the updates.

Thankyou ❤️

Use this package as a library

Depend on it

Run this command:

With Flutter:

 $ flutter pub add email_auth

This will add a line like this to your package's pubspec.yaml (and run an implicit flutter pub get):

dependencies:
  email_auth: ^1.0.0

Alternatively, your editor might support flutter pub get. Check the docs for your editor to learn more.

Import it

Now in your Dart code, you can use:

import 'package:email_auth/email_auth.dart'; 

example/lib/main.dart

import 'package:email_auth/email_auth.dart';
import 'package:flutter/material.dart';

/// Importing the configuration file to pass them to the EmailAuth instance
/// You can have a custom path and a variable name,
/// but the Map should be in the pattern {server : "", serverKey : ""}
import 'package:email_auth_example/auth.config.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  /// The boolean to handle the dynamic operations
  bool submitValid = false;

  /// Text editing controllers to get the value from text fields
  final TextEditingController _emailcontroller = TextEditingController();
  final TextEditingController _otpcontroller = TextEditingController();

  // Declare the object
  EmailAuth emailAuth;

  @override
  void initState() {
    super.initState();
    // Initialize the package
    emailAuth = new EmailAuth(
      sessionName: "Sample session",
    );

    /// Configuring the remote server
    emailAuth.config(remoteServerConfiguration);
  }

  /// a void function to verify if the Data provided is true
  /// Convert it into a boolean function to match your needs.
  void verify() {
    print(emailAuth.validateOtp(
        recipientMail: _emailcontroller.value.text,
        userOtp: _otpcontroller.value.text));
  }

  /// a void funtion to send the OTP to the user
  /// Can also be converted into a Boolean function and render accordingly for providers
  void sendOtp() async {
    bool result = await emailAuth.sendOtp(
        recipientMail: _emailcontroller.value.text, otpLength: 5);
    if (result) {
      setState(() {
        submitValid = true;
      });
    }
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: const Text('Email Auth sample'),
        ),
        body: Container(
          margin: EdgeInsets.all(5),
          child: Center(
              child: Center(
            child: Column(
              children: <Widget>[
                TextField(
                  controller: _emailcontroller,
                ),
                Card(
                  margin: EdgeInsets.only(top: 20),
                  elevation: 6,
                  child: Container(
                    height: 50,
                    width: 200,
                    color: Colors.green[400],
                    child: GestureDetector(
                      onTap: sendOtp,
                      child: Center(
                        child: Text(
                          "Request OTP",
                          style: TextStyle(
                            fontWeight: FontWeight.bold,
                            color: Colors.white,
                            fontSize: 20,
                          ),
                        ),
                      ),
                    ),
                  ),
                ),

                /// A dynamically rendering text field
                (submitValid)
                    ? TextField(
                        controller: _otpcontroller,
                      )
                    : Container(height: 1),
                (submitValid)
                    ? Container(
                        margin: EdgeInsets.only(top: 20),
                        height: 50,
                        width: 200,
                        color: Colors.green[400],
                        child: GestureDetector(
                          onTap: verify,
                          child: Center(
                            child: Text(
                              "Verify",
                              style: TextStyle(
                                fontWeight: FontWeight.bold,
                                color: Colors.white,
                                fontSize: 20,
                              ),
                            ),
                          ),
                        ),
                      )
                    : SizedBox(height: 1)
              ],
            ),
          )),
        ),
      ),
    );
  }
} 

Download Details:

Author: saran-surya

Source Code: https://github.com/saran-surya/email_auth

#flutter #email #auth 

A Flutter Package to Verify Emails using OTP