Native App Social Login
Native social login allows mobile app users to sign in using their existing Google, Facebook, or Apple accounts using platform-native SDKs.
Integration Flow
┌─────────────────┐ ┌──────────────────┐ ┌─────────────────┐│ Your App │ │ Provider SDK │ │ Horizon API │└────────┬────────┘ └────────┬─────────┘ └────────┬────────┘ │ │ │ │ 1. User taps │ │ │ "Sign in with X" │ │ │───────────────────────>│ │ │ │ │ │ 2. User authenticates │ │ │<───────────────────────│ │ │ (returns token) │ │ │ │ │ │ 3. appSocialLogin mutation │ │─────────────────────────────────────────────────>│ │ │ │ │ 4. Authentication response │ │ (Horizon token + customer info) │ │<─────────────────────────────────────────────────│Discovering Available Providers
Query the API to discover which social login providers are enabled:
query GetSocialProviders { socialLoginProviders { code name colour iconUrl clientId }}Example Response:
{ "data": { "socialLoginProviders": [ { "code": "google", "name": "Continue with Google", "colour": "#4285F4", "iconUrl": "https://example.com/google-icon.svg", "clientId": "123456789.apps.googleusercontent.com" }, { "code": "facebook", "name": "Continue with Facebook", "colour": "#1877F2", "iconUrl": "https://example.com/facebook-icon.svg", "clientId": "987654321" } ] }}| Field | Usage |
|---|---|
code | Use as providerCode in the login mutation |
name | Display text for your login button |
colour | Button background colour (hex) |
iconUrl | Provider logo for your button |
clientId | Configure your native SDK with this value |
Token Types by Platform
| Provider | Platform | Token Field | What to Send |
|---|---|---|---|
| iOS | accessToken | OAuth access token | |
| Android | authCode | Server authorization code | |
| Both | accessToken | OAuth access token | |
| Apple | Both | accessToken | Identity token (JWT) |
Google Android Note: The Android SDK returns a server authorization code instead of an access token. Request the server auth code when configuring Google Sign-In and send it as authCode.
Exchanging Token with Horizon
After the user authenticates with the provider SDK, call the appSocialLogin mutation:
mutation AppSocialLogin($input: AppBasedSocialLoginInput!) { appSocialLogin(input: $input) { authenticationResponse { error token customer { id email fullName } newCustomer } form { title fields { name label required type } } socialLoginToken socialLinkId socialIdentity { email fullName } }}Input Examples
Google (iOS):
{ "input": { "providerCode": "google", "accessToken": "ya29.a0AfH6SMBx..." }}Google (Android):
{ "input": { "providerCode": "google", "authCode": "4/P7q7W91a-oMsCeLvIaQm6bTrgtp7..." }}Facebook:
{ "input": { "providerCode": "facebook", "accessToken": "EAAGm0PX4ZCps..." }}Apple:
{ "input": { "providerCode": "apple", "accessToken": "eyJraWQiOiJXNldjT0..." }}Handling Responses
Success
When error is null, login was successful:
{ "data": { "appSocialLogin": { "authenticationResponse": { "error": null, "token": "abc123def456...", "customer": { "id": "12345", "email": "user@example.com", "fullName": "John Doe" }, "newCustomer": false } } }}Store the token securely and use it for authenticated requests. If newCustomer is true, consider showing a welcome flow.
Missing Information (INVALID_DATA)
When the social provider doesn’t supply all required data:
{ "data": { "appSocialLogin": { "authenticationResponse": { "error": "INVALID_DATA" }, "form": { "title": "Complete Your Profile", "fields": [ { "name": "email", "label": "Email Address", "required": true } ] }, "socialLoginToken": "temp-token-for-retry...", "socialIdentity": { "email": null, "fullName": "John Doe" } } }}Display a form with the fields from form.fields, pre-fill data from socialIdentity, and submit using the socialLogin mutation with missingInformation:
mutation CompleteSocialLogin($input: SocialLoginInput!) { socialLogin(input: $input) { authenticationResponse { error token customer { id email } } }}Variables:
{ "input": { "socialAuthenticationToken": "temp-token-for-retry...", "missingInformation": { "email": "user@example.com" } }}Account Linking Required (SOCIAL_LINK_PENDING)
When an account with the same email already exists:
{ "data": { "appSocialLogin": { "authenticationResponse": { "error": "SOCIAL_LINK_PENDING" }, "socialLinkId": "link-abc123", "socialIdentity": { "email": "existing@example.com" } } }}Send a verification email to confirm account ownership:
mutation RequestVerification { requestSocialLinkVerificationEmail(input: { socialAuthenticationToken: "the-social-token..." }) { error socialAuthenticationToken }}Error Reference
| Error Code | Description | Resolution |
|---|---|---|
INVALID_DATA | Missing required data | Display form, collect data, retry |
SOCIAL_LINK_PENDING | Email matches existing account | Send verification email |
INVALID_TOKEN | Provider token is invalid | Re-authenticate with provider |
EXPIRED_TOKEN | Provider token has expired | Re-authenticate with provider |
ACCOUNT_LOCKED | Account is locked | Direct user to password reset |
Using the Authentication Token
Include the token in subsequent authenticated requests:
fetch('https://api.thehut.net/myprotein/en/graphql', { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': 'Opaque abc123def456...' }, body: JSON.stringify({ query, variables })});Security Best Practices:
| Do | Don’t |
|---|---|
| Store in secure storage (Keychain, EncryptedSharedPreferences) | Store in plain text |
| Clear on logout | Log tokens to console |
| Transmit only over HTTPS | Share tokens between apps |
Managing Social Links
Logged-in users can view and manage connected social accounts:
query { customer { socialLinks(status: LINKED) { socialLinkId socialLoginProvider { code name } username status } }}Remove a social link:
mutation { removeSocialLink(input: { socialLinkId: "link-id-123" })}FAQ
Why does Google Android use authCode instead of accessToken?
Google’s Android SDK returns a server authorization code that gets exchanged server-side. This provides better security as the access token is never exposed on the device.
What if a provider isn’t in socialLoginProviders?
The provider isn’t enabled for your site. Contact your account manager to enable additional providers.
Can users link multiple social accounts?
Yes. A user can link Google, Facebook, and Apple to the same account and sign in with any of their linked providers.