{"id":34737565,"url":"https://github.com/choochmeque/simplegooglesignin","last_synced_at":"2026-05-25T02:37:07.320Z","repository":{"id":313045536,"uuid":"1049819961","full_name":"Choochmeque/SimpleGoogleSignIn","owner":"Choochmeque","description":"Lightweight, zero-dependency Google Sign-In for iOS.","archived":false,"fork":false,"pushed_at":"2025-11-02T19:21:18.000Z","size":24,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-11-02T21:13:07.807Z","etag":null,"topics":["authentication","google-signin-api","ios","oauth2","pkce","swift","swift-package-manager","zero-dependency"],"latest_commit_sha":null,"homepage":"","language":"Swift","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Choochmeque.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null},"funding":{"github":"Choochmeque","buy_me_a_coffee":"choochmeque","thanks_dev":"u/gh/choochmeque"}},"created_at":"2025-09-03T14:40:52.000Z","updated_at":"2025-11-02T19:21:22.000Z","dependencies_parsed_at":"2025-09-03T16:47:29.746Z","dependency_job_id":null,"html_url":"https://github.com/Choochmeque/SimpleGoogleSignIn","commit_stats":null,"previous_names":["choochmeque/simplegooglesignin"],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/Choochmeque/SimpleGoogleSignIn","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Choochmeque%2FSimpleGoogleSignIn","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Choochmeque%2FSimpleGoogleSignIn/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Choochmeque%2FSimpleGoogleSignIn/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Choochmeque%2FSimpleGoogleSignIn/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Choochmeque","download_url":"https://codeload.github.com/Choochmeque/SimpleGoogleSignIn/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Choochmeque%2FSimpleGoogleSignIn/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33458460,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-25T02:24:28.008Z","status":"ssl_error","status_checked_at":"2026-05-25T02:23:23.339Z","response_time":57,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["authentication","google-signin-api","ios","oauth2","pkce","swift","swift-package-manager","zero-dependency"],"created_at":"2025-12-25T03:43:43.095Z","updated_at":"2026-05-25T02:37:07.314Z","avatar_url":"https://github.com/Choochmeque.png","language":"Swift","funding_links":["https://github.com/sponsors/Choochmeque","https://buymeacoffee.com/choochmeque","https://thanks.dev/u/gh/choochmeque"],"categories":[],"sub_categories":[],"readme":"![Swift](https://img.shields.io/badge/Swift-5.7+-orange.svg)\n![iOS](https://img.shields.io/badge/iOS-13.0+-blue.svg)\n![License](https://img.shields.io/badge/license-MIT-green.svg)\n![Dependencies](https://img.shields.io/badge/dependencies-none-brightgreen.svg)\n\n# SimpleGoogleSignIn\n\nA lightweight, dependency-free Google Sign-In implementation for iOS in pure Swift.\n\n## Features\n\n✅ **Zero external dependencies** - Uses only iOS system frameworks  \n✅ **Modern OAuth 2.0 with PKCE** - Secure authentication flow  \n✅ **Token management** - Access, refresh, and ID token handling  \n✅ **Simple API** - Easy to integrate and use  \n✅ **SwiftUI \u0026 UIKit** - Compatible with both frameworks  \n✅ **Token refresh** - Built-in refresh token support  \n\n## Requirements\n\n- iOS 13.0+\n- Swift 5.7+\n- Xcode 14.0+\n\n## Installation\n\n### Swift Package Manager\n\nAdd this package to your project:\n\n```swift\ndependencies: [\n    .package(url: \"https://github.com/Choochmeque/SimpleGoogleSignIn.git\", from: \"1.0.0\")\n]\n```\n\nOr in Xcode:\n1. File → Add Package Dependencies\n2. Enter the repository URL\n3. Select \"SimpleGoogleSignIn\" library\n\n### Manual Installation\n\nSimply copy `SimpleGoogleSignIn.swift` to your project. No dependencies needed!\n\n## Setup\n\n### 1. Get Google OAuth 2.0 Credentials\n\n1. Go to [Google Cloud Console](https://console.cloud.google.com/)\n2. Create a new project or select existing\n3. Enable Google Sign-In API\n4. Create OAuth 2.0 credentials (iOS application)\n5. Add your bundle ID\n6. Copy the Client ID\n\n### 2. Configure URL Scheme\n\nAdd to your `Info.plist`:\n\n```xml\n\u003ckey\u003eCFBundleURLTypes\u003c/key\u003e\n\u003carray\u003e\n    \u003cdict\u003e\n        \u003ckey\u003eCFBundleURLSchemes\u003c/key\u003e\n        \u003carray\u003e\n            \u003c!-- Reversed client ID format --\u003e\n            \u003c!-- If your client ID is: 123456789-abcdef.apps.googleusercontent.com --\u003e\n            \u003c!-- Then your URL scheme is: com.googleusercontent.apps.123456789-abcdef --\u003e\n            \u003cstring\u003ecom.googleusercontent.apps.YOUR_CLIENT_ID\u003c/string\u003e\n        \u003c/array\u003e\n    \u003c/dict\u003e\n\u003c/array\u003e\n```\n\n### 3. Handle URL Callbacks\n\nIn your `AppDelegate` or `SceneDelegate`:\n\n```swift\nfunc application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -\u003e Bool {\n    return SimpleGoogleSignIn.shared.handleURL(url)\n}\n```\n\n## Usage\n\n### Configuration\n\n```swift\nimport SimpleGoogleSignIn\n\n// Configure on app launch\nlet configuration = GoogleSignInConfiguration(\n    clientID: \"YOUR_CLIENT_ID.apps.googleusercontent.com\",\n    serverClientID: nil, // Optional: for server-side validation\n    hostedDomain: nil    // Optional: restrict to specific domain\n)\nSimpleGoogleSignIn.shared.configure(configuration: configuration)\n```\n\n### Sign In\n\n```swift\nSimpleGoogleSignIn.shared.signIn(\n    presentingViewController: viewController,\n    hint: nil, // Optional: pre-fill email address\n    scopes: [\"openid\", \"profile\", \"email\"] // Required: OAuth scopes\n) { result in\n    switch result {\n    case .success(let signInResult):\n        print(\"Access Token: \\(signInResult.accessToken.tokenString)\")\n        print(\"ID Token: \\(signInResult.openIdToken ?? \"\")\")\n        print(\"Refresh Token: \\(signInResult.refreshToken ?? \"\")\")\n        print(\"Granted Scopes: \\(signInResult.grantedScopes ?? [])\")\n    case .failure(let error):\n        print(\"Sign in failed: \\(error)\")\n    }\n}\n```\n\n### Sign Out\n\n```swift\n// Sign out and optionally revoke access token\nSimpleGoogleSignIn.shared.signOut(accessToken: accessTokenString) { error in\n    if let error = error {\n        print(\"Sign out failed: \\(error)\")\n    } else {\n        print(\"Successfully signed out\")\n    }\n}\n\n// Or sign out without revoking token\nSimpleGoogleSignIn.shared.signOut(accessToken: nil) { error in\n    // Local sign out only\n}\n```\n\n### Token Refresh\n\n```swift\n// Refresh tokens using refresh token\nSimpleGoogleSignIn.shared.refreshTokens(refreshToken: refreshTokenString) { result in\n    switch result {\n    case .success(let signInResult):\n        print(\"New Access Token: \\(signInResult.accessToken.tokenString)\")\n        print(\"Token expires: \\(signInResult.accessToken.expirationDate ?? Date())\")\n        // Note: refreshToken may be the same as the original\n    case .failure(let error):\n        print(\"Refresh failed: \\(error)\")\n    }\n}\n```\n\n### Check Token Expiration\n\n```swift\n// GoogleToken provides expiration checking\nif accessToken.isExpired {\n    // Token has expired, refresh it\n}\n```\n\n## SwiftUI Example\n\n```swift\nimport SwiftUI\nimport SimpleGoogleSignIn\n\nstruct ContentView: View {\n    @State private var signInResult: GoogleSignInResult?\n    @State private var isSigningIn = false\n    \n    var body: some View {\n        VStack(spacing: 20) {\n            if let result = signInResult {\n                Text(\"Signed In Successfully\")\n                Text(\"Access Token: ...\\(String(result.accessToken.tokenString.suffix(10)))\")\n                \n                Button(\"Sign Out\") {\n                    SimpleGoogleSignIn.shared.signOut(accessToken: result.accessToken.tokenString) { _ in\n                        signInResult = nil\n                    }\n                }\n            } else {\n                Button(\"Sign in with Google\") {\n                    signIn()\n                }\n                .disabled(isSigningIn)\n            }\n        }\n        .padding()\n    }\n    \n    private func signIn() {\n        isSigningIn = true\n        guard let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene,\n              let rootViewController = windowScene.windows.first?.rootViewController else {\n            return\n        }\n        \n        SimpleGoogleSignIn.shared.signIn(\n            presentingViewController: rootViewController,\n            hint: nil,\n            scopes: [\"openid\", \"profile\", \"email\"]\n        ) { result in\n            isSigningIn = false\n            switch result {\n            case .success(let result):\n                signInResult = result\n            case .failure(let error):\n                print(\"Sign in failed: \\(error)\")\n            }\n        }\n    }\n}\n```\n\n## UIKit Example\n\n```swift\nimport UIKit\nimport SimpleGoogleSignIn\n\nclass SignInViewController: UIViewController {\n    private var signInResult: GoogleSignInResult?\n    \n    override func viewDidLoad() {\n        super.viewDidLoad()\n        configureGoogleSignIn()\n    }\n    \n    private func configureGoogleSignIn() {\n        let configuration = GoogleSignInConfiguration(\n            clientID: \"YOUR_CLIENT_ID.apps.googleusercontent.com\"\n        )\n        SimpleGoogleSignIn.shared.configure(configuration: configuration)\n    }\n    \n    @IBAction func signInTapped() {\n        SimpleGoogleSignIn.shared.signIn(\n            presentingViewController: self,\n            hint: nil,\n            scopes: [\"openid\", \"profile\", \"email\"]\n        ) { result in\n            switch result {\n            case .success(let result):\n                self.signInResult = result\n                self.handleSignInSuccess(result)\n            case .failure(let error):\n                self.showError(error)\n            }\n        }\n    }\n    \n    private func handleSignInSuccess(_ result: GoogleSignInResult) {\n        print(\"Access Token: \\(result.accessToken.tokenString)\")\n        // Navigate to main app or update UI\n    }\n    \n    private func showError(_ error: Error) {\n        let alert = UIAlertController(\n            title: \"Sign In Failed\",\n            message: error.localizedDescription,\n            preferredStyle: .alert\n        )\n        alert.addAction(UIAlertAction(title: \"OK\", style: .default))\n        present(alert, animated: true)\n    }\n}\n```\n\n## Comparison with Official GoogleSignIn\n\n| Feature | SimpleGoogleSignIn | Official GoogleSignIn |\n|---------|-------------------|---------------------|\n| Dependencies | None | 6+ packages |\n| Size | ~570 lines | Thousands of lines |\n| Platform | iOS only | iOS, macOS |\n| Setup Complexity | Simple | Complex |\n| App Attest | ❌ | ✅ |\n| EMM Support | ❌ | ✅ |\n| Server Auth Code | ✅ | ✅ |\n| Token Refresh | ✅ | ✅ |\n| PKCE Support | ✅ | ✅ |\n\n## Security Features\n\n- **PKCE** (Proof Key for Code Exchange) for OAuth security\n- **State parameter** verification to prevent CSRF attacks\n- **Nonce** included in authentication for additional security\n- **Token expiration** tracking and validation\n- **SSL/TLS** for all network requests\n- **ASWebAuthenticationSession** for secure system-level authentication\n\n## Error Handling\n\n```swift\nenum GoogleSignInError: LocalizedError {\n    case missingConfiguration\n    case missingPresentingViewController\n    case authenticationFailed(String)\n    case invalidResponse\n    case userCancelled\n    case networkError(Error)\n    case missingURLScheme(String)\n    \n    var errorDescription: String? {\n        switch self {\n        case .missingConfiguration:\n            return \"Google Sign-In configuration is missing\"\n        case .missingPresentingViewController:\n            return \"No presenting view controller available\"\n        case .authenticationFailed(let message):\n            return \"Authentication failed: \\(message)\"\n        case .invalidResponse:\n            return \"Invalid response from Google\"\n        case .userCancelled:\n            return \"User cancelled sign-in\"\n        case .networkError(let error):\n            return \"Network error: \\(error.localizedDescription)\"\n        case .missingURLScheme(let scheme):\n            return \"Required URL scheme '\\(scheme)' is not configured in Info.plist\"\n        }\n    }\n}\n```\n\n## License\n\nMIT License - see [LICENSE](LICENSE) file for details.\n\n## Contributing\n\nContributions are welcome! Please feel free to submit pull requests.\n\n## Support\n\nFor issues or questions, please create an issue in the repository.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fchoochmeque%2Fsimplegooglesignin","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fchoochmeque%2Fsimplegooglesignin","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fchoochmeque%2Fsimplegooglesignin/lists"}