This is an Authorization Server to be used for educational purpose only, e.g. it contains hardcoded user accounts etc.
Using docker
$ docker run -p 127.0.0.1:8080:8080 --env SECURITY_OAUTH2_REDIRECTURIS=http://frontend.local/oauthcallback --env SECURITY_JWT_SIGNINGKEY=MRzRBGrU2xtK29dcSLRLUmbwXDVxHmPT cygni/oauth2-authorization-server
Using docker-compose
version: '3.7'
services:
authorization-server:
image: cygni/oauth2-authorization-server
container_name: authorization-server
environment:
- SECURITY_OAUTH2_REDIRECTURIS=http://frontend.local/oauthcallback
- SECURITY_JWT_SIGNINGKEY=MRzRBGrU2xtK29dcSLRLUmbwXDVxHmPT
ports:
- '8080:8080'
The Authorization server support OAuth2 with Authorization Code Grant to obtain JWT access tokens. This is the recommended OAuth2 grant flow for web and mobile apps.
OAuth2 grant flows Implicit flow and Password grant are intentionally not supported as they are considered legacy and should not be your first choice.
Users and roles that are registered are the following:
| Username | Password | Role |
|---|---|---|
| [email protected] | 9J5YsK3FYjBB | ADMIN |
| [email protected] | ARvVxfCHSpFc | USER |
| [email protected] | WXTp2CMK9BZQ | USER |
One single client is registered:
| Client ID | Secret |
|---|---|
| NQqkCbse2r | ndFKcNZjyn9dbKeANtTDd3cU |
The following sections explain how you generate access_token for a user to be able to access the REST API resources.
NQqkCbse2rhttp://authorization.local/oauth/authorize?response_type=code&client_id=NQqkCbse2r&redirect_uri=http://frontend.local/oauthcallback
You are prompted with a form to enter credentials username and password.
Response:
You get redirected (301) to http://frontend.local/oauthcallback?code=EEP9ew. See the code URL param? Thats to be used to fetch the access token.
HINT: If you want to be redirected to another URI e.g. http://frontend.local/oauthcallback change the value of query param redirect_uri accordingly.
Valid values can be configured using for example docker-compose:
authorization-server:
image: cygni/oauth2-authorization-server
container_name: authorization-server
environment:
- SECURITY_OAUTH2_REDIRECTURIS=http://frontend.local/oauthcallback
- SECURITY_JWT_SIGNINGKEY=MRzRBGrU2xtK29dcSLRLUmbwXDVxHmPT
Using Client ID = NQqkCbse2r, Secret = ndFKcNZjyn9dbKeANtTDd3cU and Authorization Code = EEP9ew
$ curl --request POST -i --insecure http://authorization.local/oauth/token -H "Authorization: Basic $(echo -n NQqkCbse2r:ndFKcNZjyn9dbKeANtTDd3cU | base64)" -d code=EEP9ew -d grant_type=authorization_code -d redirect_uri=http://frontend.local/oauthcallback
Response:
HTTP/1.1 200
Cache-Control: no-store
Pragma: no-cache
X-Content-Type-Options: nosniff
X-XSS-Protection: 1; mode=block
X-Frame-Options: DENY
Content-Type: application/json
Transfer-Encoding: chunked
Date: Mon, 23 Dec 2019 16:05:05 GMT
{
"access_token" : "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX25hbWUiOiJiYWdhcm4ub2xzc29uQGN5Z25pLnNlIiwic2NvcGUiOlsiYW55Il0sImxhc3RfbmFtZSI6Ik9sc3NvbiIsImV4cCI6MTU4MDYwMTU2OSwiZmlyc3RfbmFtZSI6IkJhZ2FybiIsImF1dGhvcml0aWVzIjpbIlJPTEVfVVNFUiJdLCJqdGkiOiJjZGRiYjI5MS0xZGQ0LTQyZTEtYmJmMy1hYmEwYWY5ZmE5MTQiLCJjbGllbnRfaWQiOiJOUXFrQ2JzZTJyIn0.rGpDwu-tx10SLKfa3U3NVYiMbgggwf2snd4Vhc2exsg",
"token_type" : "bearer",
"refresh_token" : "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX25hbWUiOiJiYWdhcm4ub2xzc29uQGN5Z25pLnNlIiwic2NvcGUiOlsiYW55Il0sImF0aSI6ImNkZGJiMjkxLTFkZDQtNDJlMS1iYmYzLWFiYTBhZjlmYTkxNCIsImxhc3RfbmFtZSI6Ik9sc3NvbiIsImV4cCI6MTU4MDY4NzA2OSwiZmlyc3RfbmFtZSI6IkJhZ2FybiIsImF1dGhvcml0aWVzIjpbIlJPTEVfVVNFUiJdLCJqdGkiOiI1YTE4Nzc5OS1hMjM0LTRiZDAtYWFhNS05ZGJjYzgzYzQ5MTYiLCJjbGllbnRfaWQiOiJOUXFrQ2JzZTJyIn0.WGu_VtGi1FR_CURYwgAZ9bQPLhM8PBqs47yjXxQ-YX4",
"expires_in" : 899,
"scope" : "any",
"first_name" : "Bagarn",
"last_name" : "Olsson",
"jti" : "cddbb291-1dd4-42e1-bbf3-aba0af9fa914"
}
For the PoC the access_token is valid for 15 minutes. The refresh_token is valid for 24 hours. See details how to refresh the access_token further down in this README.
The access token is a Json Web Token (JWT). Decoded the above access_token contains the following information:
{
"user_name": "[email protected]",
"scope": [
"any"
],
"last_name": "Olsson",
"exp": 1579871135,
"first_name": "Bagarn",
"authorities": [
"ROLE_USER"
],
"jti": "8bfc4b2c-b09f-41b7-b47d-73938af8d492",
"client_id": "NQqkCbse2r"
}
$ curl --request GET -i --insecure https://resource.local/api -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX25hbWUiOiJiYWdhcm4iLCJzY29wZSI6WyJyZWFkIiwid3JpdGUiXSwibGFzdF9uYW1lIjoiT2xzc29uIiwiZXhwIjoxNTc5ODcxMTM1LCJmaXJzdF9uYW1lIjoiQmFnYXJuIiwiYXV0aG9yaXRpZXMiOlsiUk9MRV9TVVBFUlVTRVIiXSwianRpIjoiOGJmYzRiMmMtYjA5Zi00MWI3LWI0N2QtNzM5MzhhZjhkNDkyIiwiZW1haWwiOiJiYWdhcm4ub2xzc29uQGN5Z25pLnNlIiwiY2xpZW50X2lkIjoiYktVenRCVWl5MyJ9.3zBnuBSxlJCG7JrhVB8Lf5-h3PbfXQDZ2w4XkGe21F0"
Response:
HTTP/1.1 200
X-Content-Type-Options: nosniff
X-XSS-Protection: 1; mode=block
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Pragma: no-cache
Expires: 0
X-Frame-Options: DENY
Content-Type: application/json
Transfer-Encoding: chunked
Date: Mon, 23 Dec 2019 10:24:17 GMT
{
...
...
}
$ curl --request POST -i --insecure http://authorization.local/oauth/token -H "Authorization: Basic $(echo -n NQqkCbse2r:ndFKcNZjyn9dbKeANtTDd3cU | base64)" -d grant_type=refresh_token -d refresh_token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX25hbWUiOiJiYWdhcm4iLCJzY29wZSI6WyJyZWFkIiwid3JpdGUiXSwiYXRpIjoiOGJmYzRiMmMtYjA5Zi00MWI3LWI0N2QtNzM5MzhhZjhkNDkyIiwibGFzdF9uYW1lIjoiT2xzc29uIiwiZXhwIjoxNTc5OTUwMzM1LCJmaXJzdF9uYW1lIjoiQmFnYXJuIiwiYXV0aG9yaXRpZXMiOlsiUk9MRV9TVVBFUlVTRVIiXSwianRpIjoiZDkzZTJmOTQtODQzMC00NWJhLThkNGMtNTc4Mjc4NzkxYjAxIiwiZW1haWwiOiJiYWdhcm4ub2xzc29uQGN5Z25pLnNlIiwiY2xpZW50X2lkIjoiYktVenRCVWl5MyJ9.IhbDbs29nfxVGfPMqsC6B7Pg6bwsGWdBrMM9CgnKkhk
Response:
HTTP/1.1 200
Cache-Control: no-store
Pragma: no-cache
X-Content-Type-Options: nosniff
X-XSS-Protection: 1; mode=block
X-Frame-Options: DENY
Content-Type: application/json
Transfer-Encoding: chunked
Date: Mon, 23 Dec 2019 18:49:41 GMT
{
"access_token" : "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX25hbWUiOiJiYWdhcm4iLCJzY29wZSI6WyJyZWFkIiwid3JpdGUiXSwibGFzdF9uYW1lIjoiT2xzc29uIiwiZXhwIjoxNTc5ODc2Mzk3LCJmaXJzdF9uYW1lIjoiQmFnYXJuIiwiYXV0aG9yaXRpZXMiOlsiUk9MRV9TVVBFUlVTRVIiXSwianRpIjoiNTA1NTgxOGItODJmYi00YWUyLWI5ZjMtNWI1OWZkNDViODM0IiwiZW1haWwiOiJiYWdhcm4ub2xzc29uQGN5Z25pLnNlIiwiY2xpZW50X2lkIjoiYktVenRCVWl5MyJ9.9RJbtGah5cp2ErVAmPKmiKiHN8A6G8vTi3b9n6vp8-g",
"token_type" : "bearer",
"refresh_token" : "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX25hbWUiOiJiYWdhcm4iLCJzY29wZSI6WyJyZWFkIiwid3JpdGUiXSwiYXRpIjoiNTA1NTgxOGItODJmYi00YWUyLWI5ZjMtNWI1OWZkNDViODM0IiwibGFzdF9uYW1lIjoiT2xzc29uIiwiZXhwIjoxNTc5OTU1NTk3LCJmaXJzdF9uYW1lIjoiQmFnYXJuIiwiYXV0aG9yaXRpZXMiOlsiUk9MRV9TVVBFUlVTRVIiXSwianRpIjoiZWI4NzFjNzMtODkzYy00OTFkLTg2OWYtY2QzMzFkMzhhYjA3IiwiZW1haWwiOiJiYWdhcm4ub2xzc29uQGN5Z25pLnNlIiwiY2xpZW50X2lkIjoiYktVenRCVWl5MyJ9.CTngJDnpNUZ4i22TIVd_sxVgKCN9PwfZBHJgJqxZN0A",
"expires_in" : 7199,
"scope" : "any",
"first_name" : "Bagarn",
"last_name" : "Olsson",
"jti" : "5055818b-82fb-4ae2-b9f3-5b59fd45b834"
}
By design a JWT is self contained. Meaning it makes little sense to invalidate an access token. For obvious reasons --> since it is self contained.
For a client to support logout two approaches in combination should be used:
local storage or equivalent when issuing a logout event.Content type
Image
Digest
Size
268 MB
Last updated
over 6 years ago
docker pull cygni/oauth2-authorization-server