How do I get an OpenID Connect ID token from GitHub's API to implement social login? - github

Background
I'm trying to implement social login using GitHub accounts and OpenID Connect, but I can't figure out what GitHub endpoints I'm supposed to:
redirect the user to and
POST the authorization code to
...to get back an ID token, or if I already have the right endpoints but the wrong parameters.
I've been following/adapting this guide to implementing social login with OpenID Connect (which uses Google as the Identity Provider rather than GitHub) and referring to the "OAuth 2.0 web application flow" GitHub docs page to try to understand how I need to adapt the guide to work with GitHub (i.e. what GitHub endpoints and parameters I need to use).
My problem
When I POST the authorization code to https://github.com/login/oauth/access_token (the URL specified in GitHub's docs) I get back an access token and a refresh token but no ID token. I suspect this is because the GitHub docs page is meant to be used to implement a plain (non-OpenID Connect) OAuth 2.0 flow.
What I've tried
I did a lot of Googling and found these 2019 slides from PragmaticWebSecurity.com that say I need to initially redirect the user to a different endpoint (https://github.com/openid-connect/auth rather than https://github.com/login/oauth/authorize, see slide 29), but when I try to do that, I get a 404 error from GitHub. I tried emailing the guy who created those slides to ask if the endpoint had changed, but he hasn't responded to me.
These are my guesses at what the answer to my question is:
GitHub doesn't support OpenID Connect / it isn't possible to get back an ID token; I need to just use the access token to query the API to get back whatever information I need about the user.
This would explain why I can't find any mention of social login with OpenID Connect in GitHub's docs.
I have the right endpoint (https://github.com/login/oauth/access_token), but I'm missing some required parameter to get back an ID token.
I have the wrong endpoint.

I contacted GitHub Support and got an official response: Their API doesn't support OpenID Connect for social login.
Here's their full response:
Hi Nathan,
Thanks for reaching out!
GitHub OAuth flow does not currently support the OpenID connect
functionality. You'll need to use the OAuth 2.0
https://docs.github.com/en/developers/apps/building-oauth-apps/authorizing-oauth-apps
Regards,
Oluwaseun GitHub Support
So, until they add support for OpenID Connect, you can refer to this write-up I did on how to implement social login using OAuth 2.0:
How do I implement social login with GitHub accounts?

From your guesses 1) and 2).
github oauth apps currently do oauth2 not oidc, it kind of stares in your face with the name, but I missed it as well.
I'll leave this for others researching this.
oauth2 != oidc, Depending on your use case you might have a client library that supports both, the config will look the same, but the response is different and needs to be handled correctly.

As per OpenID specification, I think you'll need to authenticate with OAuth2
The primary extension that OpenID Connect makes to OAuth 2.0 to enable
End-Users to be Authenticated is the ID Token data structure. The ID
Token is a security token that contains Claims about the
Authentication of an End-User by an Authorization Server when using a
Client, and potentially other requested Claims.
...
The OpenID Connect protocol, in abstract, follows the following steps.
The RP (Client) sends a request to the OpenID Provider (OP).
The OP authenticates the End-User and obtains authorization.
The OP responds with an ID Token and usually an Access Token.
The RP can send a request with the Access Token to the UserInfo Endpoint.
The UserInfo Endpoint returns Claims about the End-User.
Then you should be able to forward through OpenID the token, once you have set up the trust between the Authentication provider and the Autorization provider.

Related

How to SSO Authorize Github API generated personal access token

I'm trying to create GitHub personal access tokens programmatically using the endpoint https://github.com/login/oauth/access_token and a GitHub App, following the device flow and code exchange.
The creation seems to be working fine and gets a response with the token
However, our account has SSO integration, and this requires all tokens to be authorized by the SSO in order to work, so the token receives a 404 response for any call to our private repositories, which I believe is related to the lack of SSO authorizing it
I can't find any documentation specifying how to authorize tokens generated via the API
IMPORTANT: I know how to authorize tokens generated via the Github Web UI, I'm talking about tokens generated via the API endpoint https://github.com/login/oauth/access_token device-flow, with code exchange! Those tokens are not available at the UI and I cannot find how to authorize them
Any idea on how to solve it?
This doesn't seem to be documented anywhere, but you need to use user oauth2
GitHub clone repo with fine-grained personal access tokens (PAT)

How should my api handle login via auth0?

I'm trying to learn how to utilize auth0 to handle user authentication for an api I am currently creating.
My api has two endpoints:
Login endpoint: /api/login
Request access token endpoint: /api/auth?code={code}
Here the authentication flow is:
User goes to the login endpoint of my api.
User is redirected to auth0 ui.
User inputs their login credentials.
Auth0 redirects back to /api/auth where a request for an access_token is made using the login code.
Firstly, is my understanding the Oauth authentication flow correct? If so, how best should my api handle the initial login redirect to auth0?
Because at the moment when I hit up /api/login from the front-end ui it just returns the html of the login page at auth0. Should I instead return a 302 with the redirect url or is it possible to create an endpoint where the user inputs the username & password via my api and avoids the redirect?
---update---
After a user has authenticated via auth0 they receive a access_token and id_token which should my api use to verify the user is who they say they are?
Not sure if my understanding is correct but I belive that my frontend ui is the OAuth client application and my API service is an OAuth resource server. As such does my api need to call out to auth0 /userinfo to verify the user?
Assuming you are trying to protect an end-user application (your question wasn't clear on that), my understanding is if you are using Auth0, you likely won't need an /api/login and api/auth API. If you are using Auth0 you can get those things during your authentication via Auth0.
I would say your APPLICATION (not API) would redirect the user to the Auth0 login endpoint. You would do that by incorporating the Auth0 SDK of choice, depending on what you're building. For example, if you're building a web app, you may choose to incorporate auth0.js and call webAuth.authorize() to trigger the login. During that login, if you have configured an API within Auth0, and you provide the proper Scope and Audience during your login, your response will return an API token.
Then your user is in a state on the client side where you are logged in, and you have a token. You can then provide that token to your API, and your API can validate that token as needed. Auth0 also has various libraries for token validation (like this spring security one, for example).
Lastly, the question on which oAuth flow to use, that also depends on what type of app you're protecting. There are again Auth0 docs to help. The flow depends on if you're building a server-side web app, a SPA, a native app, etc. Your question was a little confusing, and it sounded a bit like you are building an API and want to protect that. If there is no client-side app (only machine-to-machine API calls), then you wouldn't be dealing with HTML and login pages. You'd likely be getting into the Client Credentials flow, which last I checked was only included for Enterprise Auth0 users.

Can I authenticate a user from a Chrome Extension via their Github account without a backend server?

I am writing a Chrome extension^ and want allow users to authenticate via their Github account (targeting developers). I don't want to setup a back-end server just for authentication, because all functionalities work perfectly offline within a browser.
I have done some research. It seems that there are two options to implement OAuth without your own backend server:
Implicit grant, which github does not support
Use some other services (e.g. Auth0)
My questions are:
Can I authenticate a user via their Github account without any backend server?
If I have to what does the authentication flow look like?
^ the tool without the authentication feature can be found here.
I am going to answer my own question based on my research. Correct me if I am wrong in this answer.
Can I authenticate a user via their Github account without any backend server?
Short answer is yes. But you may not want to do it. This is because in the second step, you need to send client_secret back to Github via a POST. Normally, you cannot POST to Github.com due to the same origin policy from a regular web page. Extensions aren't so limited. Due to security reasons, you don't want to put client_secret in JavaScript.
If I have to what does the authentication flow look like?
Users are redirected to request their Github identity.
Users are redirected back to your site by Github with a temporary code.
Your application (more likely backend or native app, but not JavaScript on the front-end) POST with client_id, client_secret and code.
Github includes the access_toke in the response.
Your app accesses the API with the user's access token.

Implementing access token architecture in my API

My app logic (Android, iOS and Web) is all written in my server.
Since things got complicated, I decided to build my server as a REST web service so querying it will contain logic in the header.
My login flow is pretty simple, and I somehow tried to copy from Facebook API:
The user login to Facebook.
The user receive a Facebook access token
The access token is sent to my server with some other identifiers
The server checks with Facebook that the access token is valid with Facebook and that the other identifiers match the ones on Facebook.
The server returns an access token to the user, which he should use in each query until it expires.
The problem is that I didn't add any other restrictions like endpoints limitations (scopes) and stuff like this, so an access token generated by my server grant you access to each part of my api.
I think that inventing the wheel here will be foolish, so I'm looking for a framework or a generic solution that will allow me to add logic to the access tokens in a simple way.
I read about OAuth, but my concern that its more about user sharing with other users, but I only want to use it is login flow and scope protector.
Is it possible with OAuth ? Are there alternative to OAuth ?
That's possible with OAuth 2.0 and in fact one of the objectives: you may issue and use access tokens that have particular "scopes" (an OAuth 2.0 concept) associated to them that could relate to permissions that the client has (e.g. read/write, API A, API B).
But you need to issue your own access tokens from your own Authorization Server. You could allow users to login to that Authorization Server with their Facebook account.

REST API for website which uses Facebook for authentication

We have a website where the only way to login and authenticate yourself with the site is with Facebook (this was not my choice). The first time you login with Facebook, an account gets automatically created for you.
We now want to create an iPhone application for our site and also a public API for others to use our service.
This question is about how to authenticate with our website from the app/API and is broken into 2 parts:
What is the correct way to handle REST authentication from an API to a website which only uses Facebook OAuth as an authentication method?
I have read and researched a lot about standard methods of authentication for REST API. We can't use such methods as Basic Auth over HTTPS, as there are no credentials for a user as such. Something like this seems to be only for authenticating applications using the API.
Currently, the best way I can think is you hit an /authorize end-point on our API, it redirects to Facebook OAuth, then redirects back to the site and provides a 'token' which the user of the API can use to authenticate subsequent requests.
For an official application that we create, we wouldn't necessarily need to use the public API in the same way. What would be the best way then to talk to our website and authenticate users?
I understand (I think) how to authenticate 3rd-party applications that are using our API, using API (public) keys and secret (private) keys. However, when it comes to authenticating the user who is using the app, I am getting rather confused about how to go about it when the only way we have to authenticate a user is Facebook.
I feel like I'm missing something very obvious, or don't fully understand how public REST APIs should work, so any advice and help would be greatly appreciated.
UPDATE: see below
I've been thinking hard about this question too. It's not entirely clear to me yet but here's the route I am thinking of going. I am creating a REST API an my users only auth with Facebook connect.
On the CLIENT:
Use the Facebook API to login and get an OAUTH2 code.
Exchange this code for an access token.
In every call to my custom API I'll include the Facebook user id and the access token.
On the API (for every method that requires user authentication):
Make a request to the /me Facebook graph using the access token from above.
Verify that the Facebook user id returned matches the user id passed to my API from above.
If the access token has expired additional communication is required.
I have yet to test this. How does it sound?
--- Update: July 27th, 2014 to answer question ---
I only use the above exchange once upon login. Once I determine which user is logging in, I create my own access token, and that token is used from that point going forward. So the new flow looks like this...
On the CLIENT:
Use the Facebook API to login and get an OAUTH2 code.
Exchange this code for an access token.
Request an access token from my API, including the Facebook token as a parameter
On the API
Receive access token request.
Make a request to the /me Facebook graph using the facebook access token
Verify that the Facebook user exists and match to a user in my database
Create my own access token, save it and return it to the client to be used from this point forward
This is my implementation using JWTs (JSON Web Tokens), basically similar to Chris' updated answer. I have used Facebook JS SDK and JWT.
Here's my implementation.
Client: Use Facebook JS SDK to log in and get the access token.
Client: Request JWT from my API by calling /verify-access-token endpoint.
MyAPI: Receives access token, verify it by calling /me endpoint of Facebook API.
MyAPI: If access token is valid, finds the user from database, logs in the user if exist. Create a JWT with required fields as payload, set an expiry, sign with the secret key and send back to the client.
Client: Stores the JWT in local storage.
Client: Sends the token (the JWT from step 5) along with the request for the next API call.
MyAPI: validate the token with the secret key, if token is valid, exchange the token for a new one, send it back to the client along with the API response. (No external API calls for verification of the token here after) [if the token is invalid/expired request client to authenticate again and repeat from 1]
Client Replaces the stored token with the new one and use it for the next API call. Once the token expiry is met, the token expires revoking access to API.
Every token is used once.
Read more answers about security and JWT
How secure is JWT
If you can decode JWT how are they secure?
JSON Web Tokens (JWT) as user identification and authentication tokens
I am trying to answer the same question and have been going through a lot of reading recently...
I won't have "the" answer but things are getting a little clearer for me. Have you read the comments in the article you mentioned? I found them really interesting and helpful.
As a result, and in the light of how things have evolved since the first article has been written, here's what I think I'll do:
HTTPS everywhere — this allows you to forget about HMAC, signing, nonce, ...
Use OAuth2:
When authentication requests come from my own apps/website, use this 'trick' (or a variation of it) described in a reply to the article mentioned before.
In my case, I have two types of users: those with classic login/password credentials and those who have signed up with Facebook Connect.
So I'd provide a regular login form with a "Login with Facebook" button. If the user logs in with his "classic" credentials, I'd just send these to my OAuth2 endpoint with a grant_type=password.
If he chooses to log in via Facebook, I think that would be a two-steps process:
First, use Facebook iOS SDK to open an FBSession
When that's done and the app is given back control, there should be a way to get a Facebook ID for that user. I'd send this ID alone to my OAuth2 endpoint with an extension grant understood by my server as "using an FB User ID".
Please note that I am still heavily researching on all this stuff, so that might not be a perfect answer... maybe not even a correct one! But I think that would make for a good starting point.
The idea of using an "extension grant" for the Facebook authentication might involve having to register it to do things properly? I'm not quite sure.
Anyway, I hope I was able to help you even a bit, and that at least it can start a discussion to find the best solution to this problem :)
Update
The Facebook login is not a solution as pointed in the comments: anybody could send an arbitrary user ID and log in as this user on the API.
What about doing it like this:
Show a login form with a "Facebook login" button
If this login method is chosen, act kinda like the Facebook SDK: open a web page from your authentication server, which will initiate the Facebook login.
Once the user has logged in, Facebook will use your redirect URL to confirm; make that URL point to another endpoint of your authentication server (possibly with an extra parameter indicating the call came from an app?)
When the authentication endpoint is hit, the authentication can securely identify the user, retain its FB User ID/FB Session and return an access token to your app using a custom URL scheme, just like the Facebook SDK would do
Looks better?