I am building an Android application using Parse Server Example on Heroku as backend. I need Mailgun to send password reset emails from ParseUI class ParseLoginHelpFragment.
I haven't found an answer on how to make Mailgun work with Heroku/Parse Server. Here is my config on Heroku:
Also tried MAILGUN_SMTP_PORT 589 with the same result.
Appreciate if anyone can point out the error in my setup.
EDIT: I understand that I need to enter the Mailgun API key and some additional setup. I have tried doing that in the index.js file:
var server = ParseServer({
...otherOptions,
// Enable email verification
verifyUserEmails: true,
// The public URL of your app.
// This will appear in the link that is used to verify email addresses and reset passwords.
// Set the mount path as it is in serverURL
publicServerURL: 'https://example.com/parse',
// Your apps name. This will appear in the subject and body of the emails that are sent.
appName: 'Parse App',
// The email adapter
emailAdapter: {
module: 'parse-server-simple-mailgun-adapter',
options: {
// The address that your emails come from
fromAddress: 'parse#example.com',
// Your domain from mailgun.com
domain: 'example.com',
// Your API key from mailgun.com
apiKey: 'key-mykey',
}
}
});
However, the app crashes on Heroku, there is still something missing...
Finally got this working:
1) Make sure that your domain is verified on Mailgun by using the steps they provide.
2) Check the zone settings for your domain with your hosting provider. The exact instruction may vary depending on the provider, I use Bluehost, and these settings are in Domains>>Zone settings
3) Create a mail address at your hosting provider and enter the email and password into Mailgun settings for the domain.
4) Replace code for var api in index.js file:
var api = new ParseServer({
databaseURI: databaseUri || 'mongodb://localhost:27017/dev',
cloud: process.env.CLOUD_CODE_MAIN || __dirname + '/cloud/main.js',
appId: process.env.APP_ID || 'myAppId',
masterKey: process.env.MASTER_KEY || '', //Add your master key here. Keep it secret!
serverURL: process.env.SERVER_URL || 'http://localhost:1337/parse', // Don't forget to change to https if needed
liveQuery: {
classNames: ["Posts", "Comments"] // List of classes to support for query subscriptions
},
appName: 'Your App Name',
publicServerURL: 'https://yourappaddress.com/parse',
emailAdapter: {
module: 'parse-server-simple-mailgun-adapter',
options: {
// The address that your emails come from
fromAddress: 'yourapp#yourappaddress.com',
// Your domain from mailgun.com
domain: 'email.yourappaddress.com',
// Your API key from mailgun.com
apiKey: 'key-private-key-from-mailgun',
}
}
});
If you don't use Heroku, you don't need to use process.env.*
Hope that helps
If you didn't already do this, you need to install the parse server simple mailgun adapter using npm. Just go to the root of your parse-server-example directory: npm install parse-server-simple-mailgun-adapter.
Related
I am trying to fetch from my react native app using my local backend, and it keeps failing. The fetch doesn't even hit my backend, I made debug messages and tested on my browser to make sure the rest api worked. It works on iOS. I am also able to access other websites, so the internet works on the emulator.
UPDATE: After further debugging and trying other fetch requests, I have found a different error, maybe they are related?
error Could not open fetch.umd.js in the editor.
info When running on Windows, file names are checked against a whitelist to protect against remote code execution attacks. File names may consist only of alphanumeric characters (all languages), periods, dashes, slashes, and underscores.
I've already added "android:usesCleartextTraffic="true" in my AndroidManifest.xml. I have also tried upgrading my react native to version 63.4 but the problem persists.
It prints to console "[GET] http://127.0.0.1:8090/api/v1/user/check/email/test#gmail.com" but then the app gets
"TypeError: Network request failed"
immediately after.
When I try that URL in my browser, it properly prints
{"transok":"0","errno":"001003","errmsg":"","timestamp":"1612157175224","data":{}}
I've spent days in frustration on this, if anyone could lead me in the right direction I would be unimaginably greatful. Please let me know if any more information is needed, I will edit this question to provide the details
This is the code for the fetch which doesnt work:
const APP_SERVER_HOST = 'http://127.0.0.1:8090';
const API_BASE = APP_SERVER_HOST + '/api';
const API_VERSION = '/v1';
const API_HOST = API_BASE + API_VERSION;
isEmailExist(callback) {
var url = API_HOST + '/user/check/email/'+this.state.email;
var options = {
method: 'GET',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
}
};
console.log('[GET] ' + url);
//url is http://127.0.0.1:8090/api/v1/user/check/email/test#gmail.com
//url should post {"transok":"0","errno":"001003","errmsg":"","timestamp":"1612157175224","data":{}}
fetch(url, options).then((response) => response.json())
.then((responseData) => {
var retCode = responseData.errno;
console.log('[RTN] ' + responseData);
console.log('[RTN] ' + JSON.stringify(responseData));
if(retCode == Env.dic.ERROR_EMAIL_NOT_REG) {
console.log('[RTN] error email not reg');
return callback(false);
} else if(retCode == Env.dic.ERROR_EMAIL_EXIST){
console.log('[RTN] error email exist');
return callback(true);
}
}).done();
}
127.0.0.1 represents the emulator's localhost address. If you want to hit your machine's localhost you'll have to replace it with 10.0.2.2.
See Android docs for more information on why this is the case.
I am currently developing an android chat app. I am very new to Android Studio, JWT Token Authorization, and Django Rest Framework. Right now I am having issue to work on the Django side.
So basically I was setting up a login page from my Android, and I want it to login using phone number and password as the needed credentials. However, I also want to use JWT Token Auth to make my application more secure.
Currently I have my project urls.py pointing to one of the JWT Token API
urls.py
from django.contrib import admin
from django.urls import path,include
from django.conf.urls import include, url
from rest_framework_simplejwt import views as jwt_views
urlpatterns = [
path('admin/', admin.site.urls),
path('account/',include('restaccount.urls')) ,
path('api/token/', jwt_views.TokenObtainPairView.as_view(), name='token_obtain_pair'),
path('api/token/refresh/', jwt_views.TokenRefreshView.as_view(), name='token_refresh'),
]
This would lead to the server page which was
*PS : The phone number fields should be the default username field..(I have made some trial modifications on my code prior I post this).
I also have set up a models that was inherit from AbstractUser
models.py
class RegisterUser(AbstractUser):
phone_number = PhoneField(name='phone_number',unique=True)
birthday = models.DateField(name ='birthday',null= True)
nickname = models.CharField(max_length=100,name = 'nickname')
def __str__(self):
return self.phone_number
Currently I have tried to make a lot of modifications to my model, like :
change username = None
REQUIRED_FIELDS = []
USERNAME_FIELDS = 'phone_number'
I realize that the Token Obtain Pair View is following the Django Administration page in terms of the information that you needed (username and password).
However when I modified, I try to create superuser and try to login too Django Admin with my modified data..But I still cannot log in.. Also, I try to get token from the superuser that I have made, but it will response in "detail": "No active account found with the given credentials"
Can somebody enlighten me of the steps that I should take now?? I have tried to look for solutions but none of them solve my problem
Here's the point TLDR:
I want my app to Login using phone number and password and want to use JWT Token Auth to make it secure.
I realize the ObtainTokenPair view follows Django Admin credentials, so I have tried to modify my backend to be "log in" using phone number and password.
After I modified, I can't login to Django Admin and cannot get token with the superuser I created.
Here some of the related file attach:
Settings.py
"""
Django settings for androidapp project.
Generated by 'django-admin startproject' using Django 3.0.7.
For more information on this file, see
https://docs.djangoproject.com/en/3.0/topics/settings/
For the full list of settings and their values, see
https://docs.djangoproject.com/en/3.0/ref/settings/
"""
import os
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/3.0/howto/deployment/checklist/
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = '6qdk058^8b2#-pnw!cr1pbd(sao)vj+v69&4874zjh95xu7pg)'
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True
ALLOWED_HOSTS = ['172.31.120.211',]
# Application definition
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'rest_framework',
'restaccount',
]
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
ROOT_URLCONF = 'androidapp.urls'
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]
WSGI_APPLICATION = 'androidapp.wsgi.application'
# Database
# https://docs.djangoproject.com/en/3.0/ref/settings/#databases
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql_psycopg2',
'NAME': 'Orbital',
'USER' :'SomeUser',
'PASSWORD':'Pass',
'HOST' : 'localhost',
'PORT' : '',
}
}
# Password validation
# https://docs.djangoproject.com/en/3.0/ref/settings/#auth-password-validators
AUTH_PASSWORD_VALIDATORS = [
{
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
},
]
# Internationalization
# https://docs.djangoproject.com/en/3.0/topics/i18n/
LANGUAGE_CODE = 'en-us'
TIME_ZONE = 'UTC'
USE_I18N = True
USE_L10N = False
USE_TZ = True
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/3.0/howto/static-files/
STATIC_URL = '/static/'
AUTH_USER_MODEL = 'restaccount.RegisterUser'
#FORMAT FOR DATE INPUT
DATE_INPUT_FORMATS = ('%d-%m-%Y', '%d/%m/%Y', '%d/%m/%y', '%d %b %Y',
'%d %b, %Y', '%d %b %Y', '%d %b, %Y', '%d %B, %Y',
'%d %B %Y')
#Format for date-time input format
DATETIME_INPUT_FORMATS = ('%d/%m/%Y %H:%M:%S', '%d/%m/%Y %H:%M', '%d/%m/%Y',
'%d/%m/%y %H:%M:%S', '%d/%m/%y %H:%M', '%d/%m/%y',
'%Y-%m-%d %H:%M:%S', '%Y-%m-%d %H:%M', '%Y-%m-%d')
# Adding REST_FRAMEWORK SETTING WITH JWT AUTHENTICATION
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': [
'rest_framework_simplejwt.authentication.JWTAuthentication',
],
}
# AUTHENTICATION_BACKENDS = (
# 'django.contrib.auth.backends.ModelBackend',
# 'restaccount.backends.UserBackend'
# )
RegisterUserManager inside models.py
class RegisterUserManager(BaseUserManager):
def create_user(self, phone_number,password, **extra_fields):
if not phone_number:
raise ValueError('The phone number must be set')
user = self.model(
phone_number=phone_number,
password = password,
**extra_fields)
user.save()
return user
def create_superuser(self,phone_number,password, **extra_fields):
extra_fields.setdefault('is_staff', True)
extra_fields.setdefault('is_superuser', True)
extra_fields.setdefault('is_active', True)
# print(phone_number)
if extra_fields.get('is_staff') is not True:
raise ValueError(_('Superuser must have is_staff=True.'))
if extra_fields.get('is_superuser') is not True:
raise ValueError(_('Superuser must have is_superuser=True.'))
return self.create_user(phone_number, password,**extra_fields)
Its quite difficult to pin point the bug without getting hands-on to the actual project. I can't not find the bug or fix your project. that you have to do on your own. But I can surely share what I think would help you avoid bug and fix your project.
what I could understand
you want a custom user model
your want to use jwt authentication
so, let's begin. User model and authentication are two different things. create Custom User model first.
firstly, remove all users from database
create Custom User model following this 'A full example' exactly (check by creating superuser if custom user model is working properly, if not that means you missed something try again)
If you have successfully created custom user model that means you now have substituted 'username' with 'phone number' (in your case)
for authentication you can use custom authentication or as you tried you can use existing packages. Configure it to act as default authentication backend.
your choice of authentication package should take username and password, check if there is a user match those credentials create a token and return that token. you don't need to modify the authentication process you just provide username field(phone number) and password. Now here you might need to do something like
{username: phone_number, password: password}
because your authentication package might not support custom user.
hope it helps.
PROBLEM SOLVED
Note that my parse config in index.js did not contain clientKey, but my app IS passing a value for clientKey.
Here's the updated portion of the index.js with the clientKey added:
var api = new ParseServer({
databaseURI: databaseUri || 'mongodb://mymongodb,
cloud: process.env.CLOUD_CODE_MAIN || __dirname + '/cloud/main.js',
appId: process.env.APP_ID || 'myappid',
masterKey: process.env.MASTER_KEY || 'mymasterkey',
restAPIKey: process.env.REST_API_KEY || 'myrestapikey',
clientKey: 'myclientkey'
....
A second error I made when testing was thinking that iOS was working with respect to creating new installation records - I was incorrect, it was not working... I believe had tested an upgrade flow, and the old Parse version of the app created the installation record, thereby enabling the new parse-server version to send push to iOS. Android, however, would not work in that manner b/c the installation record required SenderID, so the parse-server version of Android was unable to work after upgrading (like iOS was).
ORIGINAL QUESTION BELOW
I've followed all the migration instructions to switch over from Parse to parse-server. Parse-server is working fine for iOS.
With Android, I am sometimes getting unauthorized when trying to save the parse installation. I'll consistently get unauthorized on a particular device until it works once.
Once a the installation record save succeeds, all subsequent calls to save the installation record seem to work.
Here's the relevant Android code:
String parseAppId = getString(R.string.parse_app_id);
String parseClientKey = getString(R.string.parse_client_key);
String parseServer = getString(R.string.parse_server);
Parse.initialize(new Parse.Configuration.Builder(this)
.applicationId(parseAppId)
.clientKey(parseClientKey)
.server(parseServer)
.build()
);
ParseInstallation parseInstallation = ParseInstallation.getCurrentInstallation();
parseInstallation.saveEventually(new SaveCallback() {
#Override
public void done(ParseException e) {
// e = com.parse.ParseRequest$ParseRequestException: unauthorized
}
}
Here's my server config in index.js (actual values redacted):
var api = new ParseServer({
databaseURI: databaseUri || 'mongodb://mymongodb,
cloud: process.env.CLOUD_CODE_MAIN || __dirname + '/cloud/main.js',
appId: process.env.APP_ID || 'myappid',
masterKey: process.env.MASTER_KEY || 'mymasterkey',
restAPIKey: process.env.REST_API_KEY || 'myrestapikey',
serverURL: process.env.SERVER_URL || 'https://my.server.com/parse',
liveQuery: {
classNames: ["Posts", "Comments"] // List of classes to support for query subscriptions
},
push: {
android: {
senderId: 'mysenderid',
apiKey: 'myapikey'
},
ios: {
pfx: __dirname + '/certs/myp12file.p12',
bundleId: 'my.bundle.id',
production: true
}
},
verbose: true
});
I've verified and re-verified a million times the AppId, ClientKey, and Server settings... they're identical to what I have in the parse config in the index.js file, and iOS and Android values are identical (copied and pasted), with the exception that Android has an extra trailing slash "/" at the end of the server URL (as noted in the setup docs and other SO questions).
One similar issue I found was this one:https://github.com/ParsePlatform/parse-server/issues/635
But since my AppId matches, that can't be causing what's happening.
This site notes that when the AppId is updated, it can cause the 403 response because parse caches old AppId and ClientKey values:
http://androidetc.com/android/tutorial_parse_server_android_heroku_mongodb/
However, the client key and AppId are unchanged from Parse. Also, I'm getting this with new emulators now as well.
I was also previously using 'saveInBackground' instead of 'saveEventually', and saw a note that said the unauthorized error might be fixed by it.
I'm using the current android sdk for parse: (from my build.gradle)
compile 'com.parse:parse-android:1.13.1'
I also have two emulators that are able to save the parse installation when running with the same code, but fail if I try to save with any other values (I separated the additional values into a separate call that I'm doing after the first installation save attempt - I wanted to see if it made a difference if I tried to save with or without the additional values... and for some devices, it does?):
parseInstallation.put("email", email);
parseInstallation.put("userID", userID);
parseInstallation.put("campusID", campusID);
parseInstallation.put("GCMSenderId", "...senderid...");
(Yes I realize that I should store those values in another table - TBD later)
...
deleted irrelevant info from initial post
Note that my parse config in index.js did not contain clientKey, but my app IS passing a value for clientKey.
Here's the updated portion of the index.js with the clientKey added:
var api = new ParseServer({
databaseURI: databaseUri || 'mongodb://mymongodb,
cloud: process.env.CLOUD_CODE_MAIN || __dirname + '/cloud/main.js',
appId: process.env.APP_ID || 'myappid',
masterKey: process.env.MASTER_KEY || 'mymasterkey',
restAPIKey: process.env.REST_API_KEY || 'myrestapikey',
clientKey: 'myclientkey'
A second error I made when testing was thinking that iOS was working with respect to creating new installation records - I was incorrect, it was not working... I believe had tested an upgrade flow with iOS, and the old Parse version of the app created the installation record, thereby enabling the new parse-server version to send push to iOS. Android, however, would not work in that manner b/c the installation record required SenderID, so the parse-server version of Android was unable to work after upgrading (like iOS was).
I just had my first contacts with the ionic framework. I've worked with Phonegap and AngularJS before however, so it was not all that new to me.
I found out that there is this new feature to use Google Cloud Messaging push notifications in Ionic, through the Ionic Push feature (http://blog.ionic.io/announcing-ionic-push-alpha/).
Related lines of code from app.js
angular.module('starter', ['ionic','ionic.service.core', 'starter.controllers', 'starter.services'])
.run(function($ionicPlatform) {
$ionicPlatform.ready(function() {
// Hide the accessory bar by default (remove this to show the accessory bar above the keyboard
// for form inputs)
if (window.cordova && window.cordova.plugins && window.cordova.plugins.Keyboard) {
cordova.plugins.Keyboard.hideKeyboardAccessoryBar(true);
cordova.plugins.Keyboard.disableScroll(true);
}
if (window.StatusBar) {
// org.apache.cordova.statusbar required
StatusBar.styleLightContent();
}
// enable push notifications
Ionic.io();
// enable users (http://docs.ionic.io/docs/user-quick-start)
// this will give you a fresh user or the previously saved 'current user'
var user = Ionic.User.current();
// if the user doesn't have an id, you'll need to give it one.
if (!user.id) {
user.id = Ionic.User.anonymousId();
// user.id = 'your-custom-user-id';
}
console.log('user-id:' + user.id);
//persist the user
user.save();
var push = new Ionic.Push({
"debug": true,
"onNotification": function(notification) {
var payload = notification.payload;
console.log(notification, payload);
},
"onRegister": function(data) {
console.log(data.token);
}
});
push.register(function(token) {
console.log("Device token:",token.token);
});
push.addTokenToUser(user);
console.log('token added to user');
});
})
Log from ionic serve
ionic $ 0 361081 log Ionic Core:, init
1 361083 log Ionic Core:, searching for cordova.js
2 361085 log Ionic Core:, attempting to mock plugins
3 361155 log user-id:1cc3d21c-b687-4988-b944-ad07b1a677c8
4 361158 log Ionic Push:, a token must be registered before you can add it to a user.
5 361159 log Ionic Push:, token is not a valid Android or iOS registration id. Cannot save to user.
6 361159 log token added to user
7 361160 log Ionic Push:, register
8 361160 error ReferenceError: PushNotification is not defined, http://localhost:8100/lib/ionic-platform-web-client/dist/ionic.io.bundle.min.js, Line: 2
9 361526 log Ionic User:, saved user
Any input is welcome, I am also more than happy to provide more information if needed.
EDIT 10/05/2015:
found out that dev_push = false only works on physical devices, not in browser
I tried to add token to user before even registering the user
I'm having the same problem, seems not many answers online at the moment.
but even on real device, it won't save the token to user.
I just had to decide go live without push first, then use ionic deploy to follow up.
also I think you have to put this line
push.addTokenToUser(user);
inside the register callback according to this doc
http://docs.ionic.io/docs/push-usage
You also need to declare 'ionic.service.push' as a dependency in your angular module if you'd like to use it.
angular.module('starter', ['ionic','ionic.service.core', 'ionic.service.push'])
I have it like this and it works:
Ionic.io();
var user = Ionic.User.current();
if (!user.id) {
user.id = Ionic.User.anonymousId();
// save our newly created user
user.save();
}
var push = new Ionic.Push({});
push.register(function (token) {
console.log("Got Token:", token.token);
// now we have token, so add it to user
push.addTokenToUser(user);
// don't forget to save user to Ionic Platform with our new token
user.save();
});
// set this user as current, so we can acess him later
Ionic.User.current(user);
Did you use this
ionic config set dev_push true-if testing in emulator or laptop
ionic config set dev_pushfalse - if testing on the phone
ionic push --google-api-key Your API Key
ionic config set gcm_key Project Number
Your token is the registration id that is unique for a particular device. That is sent to you by android.
Your Phone (With the API Key)---------> to Google's GCM
Google GCM (recognises it's you via your Project number and API key) -----> Oh it's you let me make a note of it. (Save a token id in it's DB and send's one to you.)
You get a registration id unique for your device(will change if an app is uninstalled).
You call your server say hey it's me your user. Please Notify me if you get something.
Server obliges, says, okay dude, I got this. Saves the registration id with your details probably your username in it's DB.
Now from Server.
I need to inform my users about a great deal(or an accident or something).
Pull up all targeted registration Id's from DB(maybe on some condition)
registrationIds.push(regId) //in a loop
and sender.send(message, registration, function(err, result){
});
Send to Google. Google see's oh only these many people(not all maybe) from this API Key need a notification. no Problem I will notify them and you receive a notification, my dear friend.
As mentioned in the link , Adding token to the $ionicUser is done by doing , user.addPushToken(pushToken); .
For this to work you should first configure the app not to use developement pushes by ,
ionic config set dev_push true
After initialising Ionic.io and Ionic.push , load the user or create one with a new random id ,
Ionic.io();
var push = new Ionic.Push();
Ionic.User.load(localStorage.id).then(function (user) {
Ionic.User.current(user);
pushFactory.register(push, user);
}, function (error) {
/*the user with that id is not present , so create one with a random id and register the push */
});
The push factory is defined as below,
function pushFactory() {
return {
'register': function (push, user) {
push.register(function (pushToken) {
user.addPushToken(pushToken);
user.save().then(function (answer) {
console.log('user saved'+answer);
})
})
}
}
}
I'm developing a Sinatra app for which I'd like to use OmniAuth. So far, I have something similar to this for the web app:
http://codebiff.com/omniauth-with-sinatra
I'd like the web app to be usable via Android phones which would use an API, authenticating by means of a token. The development of an API seems to be covered nicely here:
Sinatra - API - Authentication
What is not clear is now I might arrange the login procedure. Presumably it would be along these lines:
User selects what service to use, e.g. Twitter, FaceBook &c., by means of an in-app button on the Android device.
The Android app opens a webview to log in to the web app.
A token is somehow created, stored in the web app's database, and returned to the Android app so that it can be stored and used for subsequent API requests.
I'm not very clear on how point 3 might be managed - does anyone have any suggestions?
As no-one seems to have any suggestions, here's what I've come up with so far. I don't think it's very good, though.
I've added an API key to the user model, which is created when the user is first authenticated:
class User
include DataMapper::Resource
property :id, Serial, :key => true
property :uid, String
property :name, String
property :nickname, String
property :created_at, DateTime
property :api_key, String, :key => true
end
....
get '/auth/:name/callback' do
auth = request.env["omniauth.auth"]
user = User.first_or_create({ :uid => auth["uid"]},
{ :uid => auth["uid"],
:nickname => auth["info"]["nickname"],
:name => auth["info"]["name"],
:api_key => SecureRandom.hex(20),
:created_at => Time.now })
session[:user_id] = user.id
session[:api_key] = user.api_key
flash[:info] = "Welcome, #{user.name}"
redirect "/success/#{user.id}/#{user.api_key}"
end
If the authorisation works then the api_key is supplied to the Android app, which will presumably store it on the device somewhere:
get '/success/:id/:api_key', :check => :valid_key? do
user = User.get(params[:id],params[:api_key])
if user.api_key == params[:api_key]
{'api_key' => user.api_key}.to_json
else
error 401
end
end
All API calls are protected as in the link in my original post:
register do
def check (name)
condition do
error 401 unless send(name) == true
end
end
end
helpers do
def valid_key?
user = User.first(:api_key => params[:api_key])
if !user.nil?
return true
end
return false
end
end
For public use I'll only allow SSL connections to the server. Any suggestions for improvement would be welcome.