Skip to content

Commit

Permalink
🛂 Devicecode auth
Browse files Browse the repository at this point in the history
  • Loading branch information
LNA-DEV committed Oct 31, 2024
1 parent 8ac80ab commit 4885dbe
Show file tree
Hide file tree
Showing 4 changed files with 108 additions and 2 deletions.
88 changes: 88 additions & 0 deletions lib/auth/device_code.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
import 'dart:convert';
import 'package:http/http.dart' as http;
import 'package:open_media_server_app/globals.dart';

class DeviceCode {
Future<Map<String, dynamic>> getDeviceCode(
String clientId, String scope, String deviceCodeUrl) async {
final response = await http.post(
Uri.parse(deviceCodeUrl), // Replace with your provider's URL
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
body: {'client_id': clientId, 'scope': scope},
);

if (response.statusCode == 200) {
return json.decode(response.body);
} else {
throw Exception('Failed to get device code');
}
}

Future<String?> authenticateUser(
String clientId, String scope, String deviceCodeUrl) async {
try {
final deviceCodeResponse =
await getDeviceCode(clientId, scope, deviceCodeUrl);
final userCode = deviceCodeResponse['user_code'];
final verificationUri = deviceCodeResponse['verification_uri'];

print('Please go to $verificationUri?code=$userCode');

final code = deviceCodeResponse['device_code'];
final interval = deviceCodeResponse['interval'];
var token = await pollForToken(
code, interval, Globals.ClientId, Globals.TokenUrl);

return token;
} catch (e) {
print('Error: $e');
}

return null;
}

Future<String?> pollForToken(
String deviceCode, int interval, String clientId, String tokenUrl) async {
while (true) {
await Future.delayed(Duration(seconds: interval));

final response = await http.post(
Uri.parse(tokenUrl), // Replace with your provider's token URL
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
body: {
'client_id': clientId,
'grant_type': 'urn:ietf:params:oauth:grant-type:device_code',
'device_code': deviceCode,
},
);

if (response.statusCode == 200) {
final tokenResponse = json.decode(response.body);
print('Access token: ${tokenResponse['access_token']}');

return tokenResponse['access_token'];
} else {
final errorResponse = json.decode(response.body);
if (errorResponse['error'] == 'authorization_pending') {
print('Authorization pending...');
continue;
} else if (errorResponse['error'] == 'authorization_declined') {
print('Authorization declined by user');
break;
} else if (errorResponse['error'] == 'expired_token') {
print('Device code expired');
break;
} else {
print('Unknown error: ${errorResponse['error']}');
break;
}
}
}

return null;
}
}
16 changes: 14 additions & 2 deletions lib/auth/login_manager.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import 'package:flutter/foundation.dart';
import 'package:oauth2_client/access_token_response.dart';
import 'package:oauth2_client/interfaces.dart';
import 'package:oauth2_client/oauth2_client.dart';
import 'package:open_media_server_app/auth/device_code.dart';
import 'package:open_media_server_app/globals.dart';
import 'package:open_media_server_app/helpers/Preferences.dart';
import 'package:random_string/random_string.dart';
Expand All @@ -15,7 +16,9 @@ class LoginManager {
BaseWebAuth? baseWebAuth;

LoginManager() {
if (!Globals.isWeb) {
if (Globals.isTv) {
// Do nothing
} else if (!Globals.isWeb) {
client = OAuth2Client(
authorizeUrl: Globals.AuthorizeUrl,
tokenUrl: Globals.TokenUrl,
Expand All @@ -40,6 +43,15 @@ class LoginManager {
}

Future<String?> login(String clientId, String clientSecret) async {
if (Globals.isTv) {
DeviceCode deviceCode = DeviceCode();
var token = await deviceCode.authenticateUser(Globals.ClientId, "offline_access", Globals.DeviceCodeUrl);

Preferences.prefs?.setString("AccessToken", token!);

return token;
}

var state = Preferences.prefs?.getString("OAuth_State");
var codeVerifier = Preferences.prefs?.getString("OAuth_CodeVerifier");

Expand Down Expand Up @@ -82,4 +94,4 @@ class LoginManager {

return tknResponse.accessToken;
}
}
}
2 changes: 2 additions & 0 deletions lib/globals.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,14 @@ class Globals {
static String ClientSecret = "";
static String AuthorizeUrl = "";
static String TokenUrl = "";
static String DeviceCodeUrl = "";

static String Title = "Open Media Station";
static String PictureNotFoundUrl =
"https://static.vecteezy.com/system/resources/previews/005/337/799/original/icon-image-not-found-free-vector.jpg";

static bool isTv = false;
static bool isAndroidTv = false;
static bool isMobile = false;
static bool isWeb = false;
}
4 changes: 4 additions & 0 deletions lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@ Future main() async {
Globals.isMobile = false;
}

if (Globals.isTv && defaultTargetPlatform == TargetPlatform.android) {
Globals.isAndroidTv = true;
}

if (kIsWeb) {
Globals.isWeb = true;
}
Expand Down

0 comments on commit 4885dbe

Please sign in to comment.