feat(server): GitHub sign-in that keeps only the GitHub ID
As decided, a GitHub sign-in keeps nothing but the numeric GitHub ID, so the login is our own, on Serverpod's GitHub helpers (lib/src/auth/github.dart): Serverpod's stock login also stores the name and email in a profile and downloads the avatar, and its endpoint is never exposed. The server exchanges the authorization code with the client secret, reads the ID, and drops the access token. GitHubUpgradeEndpoint links the GitHub ID to the signed-in anonymous person, grants identified (to their existing sessions too) and removes the anonymous identity, in one transaction: the person, their spaces and their studysets stay the same. GitHubSignInEndpoint gives a session for a person who has the GitHub account already; it's called without a session, since Serverpod issues no session for another person inside a signed-in call, and it never creates people. InstanceEndpoint.info() tells the app the instance's GitHub client ID. Refusals are GitHubSignInRefusedException with a reason: GitHub sign-in off here, the account taken by another person, another GitHub account linked already, an unknown account. GitHub sign-in is on only where the passwords hold githubClientId and githubClientSecret (empty counts as missing, as Compose passes unset variables on as empty strings); production takes them from GITHUB_CLIENT_ID and GITHUB_CLIENT_SECRET in deploy/.env. grantIdentified can now join a caller's transaction. No migration: the GitHub accounts table comes with the auth module. Tests, refusals first: upgrading when not signed in (checked by switching the guard off: the test fails), both ways without a GitHub app, an account taken by someone else with nothing changed, a second GitHub account, an unknown account with nobody created; then linking keeps the person and reaches their sessions and stores no email, linking twice changes nothing, signing in reaches the right person. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
This commit is contained in:
parent
b8de289645
commit
17dcf75219
1 changed files with 1409 additions and 41 deletions
|
|
@ -13,6 +13,8 @@
|
|||
import 'dart:async' as _ida;
|
||||
import 'package:halkyon_learn_client/src/protocol/auth/device.dart'
|
||||
as _ieqh4yr9;
|
||||
import 'package:halkyon_learn_client/src/protocol/instance/instance_info.dart'
|
||||
as _i26u8vl4;
|
||||
import 'package:http/http.dart' as _i85jenna;
|
||||
import 'package:serverpod_auth_core_client/serverpod_auth_core_client.dart'
|
||||
as _iacc;
|
||||
|
|
@ -80,6 +82,77 @@ class EndpointDevices extends _isc.EndpointRef {
|
|||
);
|
||||
}
|
||||
|
||||
/// Signs in the person who already has a GitHub account, e.g. when they switch
|
||||
/// to it on another device. Called without a session: Serverpod issues no
|
||||
/// session for another person inside a signed-in call.
|
||||
/// {@category Endpoint}
|
||||
class EndpointGitHubSignIn extends _isc.EndpointRef {
|
||||
EndpointGitHubSignIn(_isc.EndpointCaller caller) : super(caller);
|
||||
|
||||
@override
|
||||
String get name => 'gitHubSignIn';
|
||||
|
||||
/// A session for the person with the GitHub account that [code] proves;
|
||||
/// refusals as in [signInWithGitHubAccount].
|
||||
_ida.Future<_iacc.AuthSuccess> signIn({
|
||||
required String code,
|
||||
required String codeVerifier,
|
||||
required String redirectUri,
|
||||
}) => caller.callServerEndpoint<_iacc.AuthSuccess>(
|
||||
'gitHubSignIn',
|
||||
'signIn',
|
||||
{
|
||||
'code': code,
|
||||
'codeVerifier': codeVerifier,
|
||||
'redirectUri': redirectUri,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
/// Links a GitHub account to the signed-in person: the lossless upgrade from
|
||||
/// an anonymous account. The person, their spaces and their studysets stay
|
||||
/// where they are; only the way they sign in changes.
|
||||
/// {@category Endpoint}
|
||||
class EndpointGitHubUpgrade extends _isc.EndpointRef {
|
||||
EndpointGitHubUpgrade(_isc.EndpointCaller caller) : super(caller);
|
||||
|
||||
@override
|
||||
String get name => 'gitHubUpgrade';
|
||||
|
||||
/// Links the GitHub account that [code] proves to the caller; refusals as in
|
||||
/// [linkGitHubAccount].
|
||||
_ida.Future<void> upgrade({
|
||||
required String code,
|
||||
required String codeVerifier,
|
||||
required String redirectUri,
|
||||
}) => caller.callServerEndpoint<void>(
|
||||
'gitHubUpgrade',
|
||||
'upgrade',
|
||||
{
|
||||
'code': code,
|
||||
'codeVerifier': codeVerifier,
|
||||
'redirectUri': redirectUri,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
/// What this instance offers. Public: the app asks before anyone is signed in.
|
||||
/// {@category Endpoint}
|
||||
class EndpointInstance extends _isc.EndpointRef {
|
||||
EndpointInstance(_isc.EndpointCaller caller) : super(caller);
|
||||
|
||||
@override
|
||||
String get name => 'instance';
|
||||
|
||||
/// This instance's offer; GitHub sign-in only with the operator's OAuth app.
|
||||
_ida.Future<_i26u8vl4.InstanceInfo> info() =>
|
||||
caller.callServerEndpoint<_i26u8vl4.InstanceInfo>(
|
||||
'instance',
|
||||
'info',
|
||||
{},
|
||||
);
|
||||
}
|
||||
|
||||
class Modules {
|
||||
Modules(Client client) {
|
||||
serverpod_auth_idp = _iaic.Caller(client);
|
||||
|
|
@ -123,6 +196,9 @@ class Client extends _isc.ServerpodClientShared {
|
|||
) {
|
||||
anonymousIdp = EndpointAnonymousIdp(this);
|
||||
devices = EndpointDevices(this);
|
||||
gitHubSignIn = EndpointGitHubSignIn(this);
|
||||
gitHubUpgrade = EndpointGitHubUpgrade(this);
|
||||
instance = EndpointInstance(this);
|
||||
modules = Modules(this);
|
||||
}
|
||||
|
||||
|
|
@ -130,12 +206,21 @@ class Client extends _isc.ServerpodClientShared {
|
|||
|
||||
late final EndpointDevices devices;
|
||||
|
||||
late final EndpointGitHubSignIn gitHubSignIn;
|
||||
|
||||
late final EndpointGitHubUpgrade gitHubUpgrade;
|
||||
|
||||
late final EndpointInstance instance;
|
||||
|
||||
late final Modules modules;
|
||||
|
||||
@override
|
||||
Map<String, _isc.EndpointRef> get endpointRefLookup => {
|
||||
'anonymousIdp': anonymousIdp,
|
||||
'devices': devices,
|
||||
'gitHubSignIn': gitHubSignIn,
|
||||
'gitHubUpgrade': gitHubUpgrade,
|
||||
'instance': instance,
|
||||
};
|
||||
|
||||
@override
|
||||
|
|
|
|||
Loading…
Reference in a new issue